@ductape/mcp 0.1.60 → 0.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 ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 - 2026-07-26
4
+
5
+ - Added exhaustive AI-led migration guidance for TypeScript, Go, Java, and .NET.
6
+ - Added original E2E gates, contextual review, semantic database and frontend guidance, and strict verification matrices.
7
+ - Added dependency-aware large-repository guidance.
8
+ - Reinforced the administrative CLI/runtime execute boundary and access-key isolation.
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Ductape MCP Server
2
2
 
3
+ Migration guidance is available from `ductape_docs({ topic: "migration" })`. It starts with an original E2E
4
+ baseline, defaults to a separate new codebase, requires contextual review and strict parity evidence, and ends
5
+ against the unchanged original E2E suite. Administrative work uses `ductape_cli`; `ductape_execute` remains
6
+ publishable-key runtime-only. MCP never accepts or forwards `DUCTAPE_ACCESS_KEY`.
7
+
3
8
  MCP (Model Context Protocol) server that exposes **Ductape SDK** operations as tools. All calls go through the **Ductape backend proxy** at a fixed URL; the SDK never runs in the MCP process. It is completely stateless; you provide your **Publishable Key** per execution.
4
9
 
5
10
  ## Prerequisites
package/dist/index.js CHANGED
@@ -946,7 +946,7 @@ const payloadGenerateInputSchema = z.object({
946
946
  execution_context: z.enum(['user', 'delegated', 'system']).optional().default('user').describe('Actor intent for this runtime operation. "user" means an active request initiated by the authenticated user; ' +
947
947
  '"delegated" means work acting on behalf of a user with a short-lived delegated identity or application-owned ' +
948
948
  'immutable actor context; "system" means intentionally unattributed background work. This drives session warnings.'),
949
- include_cache: z.boolean().optional().default(true).describe('Include the cache tag inside the generated input object so the caller knows which cache to reference for this query.'),
949
+ include_cache: z.boolean().optional().describe('Include a cache tag inside the generated payload. Defaults to false; set true only when the runtime call should use cache explicitly.'),
950
950
  schema_mode: z.enum(['strict', 'best_effort']).optional().default('best_effort').describe('"strict" — fail if any required field cannot be resolved. ' +
951
951
  '"best_effort" — fill what is known, leave unknowns as null/placeholder. Use best_effort when exploring.'),
952
952
  input_hint: z.record(z.any()).optional().describe('Optional. Partial input values you already know. These are merged into the generated payload template ' +
@@ -1135,14 +1135,28 @@ const ADMIN_SUBCOMMANDS = [
1135
1135
  'events',
1136
1136
  'cloud',
1137
1137
  'secrets',
1138
+ 'secrets-import-env',
1138
1139
  'generate',
1139
1140
  'apply',
1140
1141
  'db',
1141
1142
  'graph',
1143
+ 'migrate-codebase',
1144
+ 'migration-review',
1145
+ 'migration-slice',
1146
+ 'migration-portfolio',
1147
+ 'migration-database',
1148
+ 'migration-environments',
1149
+ 'migration-products',
1150
+ 'migration-secrets',
1142
1151
  ];
1143
1152
  function checkCli() {
1144
1153
  try {
1145
- const out = execSync('ductape --version', { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
1154
+ const out = execSync('ductape --version', {
1155
+ encoding: 'utf8',
1156
+ timeout: 5000,
1157
+ stdio: ['pipe', 'pipe', 'pipe'],
1158
+ env: cliEnvironment(),
1159
+ }).trim();
1146
1160
  return { available: true, version: out || 'unknown' };
1147
1161
  }
1148
1162
  catch {
@@ -1158,6 +1172,7 @@ function checkLoginState() {
1158
1172
  encoding: 'utf8',
1159
1173
  timeout: 10000,
1160
1174
  stdio: ['pipe', 'pipe', 'pipe'],
1175
+ env: cliEnvironment(),
1161
1176
  });
1162
1177
  authState = 'ok';
1163
1178
  return 'ok';
@@ -1173,7 +1188,12 @@ function syncWorkspace() {
1173
1188
  if (!target)
1174
1189
  return;
1175
1190
  try {
1176
- execSync(`ductape workspaces use "${target}"`, { encoding: 'utf8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
1191
+ execSync(`ductape workspaces use "${target}"`, {
1192
+ encoding: 'utf8',
1193
+ timeout: 10000,
1194
+ stdio: ['pipe', 'pipe', 'pipe'],
1195
+ env: cliEnvironment(),
1196
+ });
1177
1197
  }
1178
1198
  catch {
1179
1199
  // best-effort; if it fails the user will see workspace-mismatch errors on subsequent commands
@@ -1200,6 +1220,7 @@ function runCli(command) {
1200
1220
  // instead of this wrapper killing the CLI first and reducing it to "(no data)".
1201
1221
  timeout: 90000,
1202
1222
  stdio: ['pipe', 'pipe', 'pipe'],
1223
+ env: cliEnvironment(),
1203
1224
  });
1204
1225
  return { success: true, output: output.trim() };
1205
1226
  }
@@ -1243,13 +1264,431 @@ function runCli(command) {
1243
1264
  return { success: false, output: msg };
1244
1265
  }
1245
1266
  }
1267
+ /**
1268
+ * MCP is publishable-key-only. The standalone CLI may manage its own access-key
1269
+ * credentials, but an access key present in the MCP host environment is never
1270
+ * forwarded into CLI subprocesses.
1271
+ */
1272
+ function cliEnvironment() {
1273
+ const environment = { ...process.env };
1274
+ delete environment.DUCTAPE_ACCESS_KEY;
1275
+ return environment;
1276
+ }
1277
+ function shellArgument(value) {
1278
+ return `'${value.replace(/'/g, `'\\''`)}'`;
1279
+ }
1246
1280
  const docsInputSchema = z.object({
1247
1281
  topic: z.string().describe('Feature topic to look up. Supported: ' +
1248
1282
  'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
1249
1283
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
1250
- 'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue'),
1284
+ 'notifications, resilience, features, events, logs, migration, frontend, frontend-analytics, client, react, vue'),
1285
+ });
1286
+ const migrationInputSchema = z.object({
1287
+ source: z.string().describe('Absolute path to the existing codebase.'),
1288
+ e2e_baseline: z.string().describe('Absolute path to a passing migration-e2e baseline manifest created before migration inspection.'),
1289
+ mode: z.enum(['in-place', 'new-codebase']).default('new-codebase').describe('Selects where advisory guidance is written. It never generates or rewrites application code.'),
1290
+ destination: z.string().optional().describe('Required destination path for new-codebase mode.'),
1291
+ product: z.string().optional().describe('Ductape product tag; defaults to a slug of the source directory name.'),
1292
+ name: z.string().optional().describe('Product display name.'),
1293
+ database: z.string().optional().describe('Target database tag recorded for the AI review; no schema is generated.'),
1294
+ max_file_bytes: z.number().int().positive().optional().default(2_000_000),
1295
+ include: z.array(z.string()).optional().default([]).describe('Repository-relative glob patterns to include.'),
1296
+ exclude: z.array(z.string()).optional().default([]).describe('Repository-relative glob patterns to exclude with audit evidence.'),
1297
+ ensure_product: z.boolean().optional().default(false).describe('Create the product through the standalone authenticated CLI when it does not exist.'),
1298
+ write: z.boolean().optional().default(false).describe('Write redacted advisory artifacts only. This never writes application code or executable Ductape assets.'),
1251
1299
  });
1252
1300
  const DOCS = {
1301
+ migration: `
1302
+ DUCTAPE CODEBASE MIGRATION GUIDE
1303
+
1304
+ NON-NEGOTIABLE AUTOMATION BOUNDARY
1305
+ The scanner is an evidence collector and standards engine, not a code generator or codemod.
1306
+ Scanner findings are evidence, not implementation instructions.
1307
+ It MUST NOT create, rewrite, patch, or mechanically replace application source.
1308
+ It MUST NOT emit executable migrations or authoritative Ductape assets.
1309
+ The scanner does not generate or propose a schema. Schema decisions belong to the contextual AI review.
1310
+ migration-evidence.json is checksummed source evidence, never an executable migration.
1311
+ The AI must inspect relevant source files and installed SDK APIs, explain its design, and then write
1312
+ code through normal editing tools. Builds, tests, rescans, inventory checks, and smoke tests verify it.
1313
+
1314
+ SUPPORTED SERVER LANGUAGES
1315
+ TypeScript/Node.js (including NestJS), Go, Java, and .NET.
1316
+ Inspect installed package exports before generating code; language APIs pursue parity but signatures differ.
1317
+
1318
+ START
1319
+ 1. Inspect the original project and create or complete project-level E2E tests before changing application code.
1320
+ Run them against the original codebase. The AI executes the project test command with normal coding tools;
1321
+ Ductape CLI only records evidence and never executes an arbitrary command.
1322
+ Create a value-free definition containing command, suite_files, and passing baseline status/evidence/environment:
1323
+ ductape_cli("migration-e2e init --source <source> --definition <baseline-definition.json> --output <e2e-baseline.json> --json")
1324
+ The manifest SHA-256 binds every original test/fixture. Preserve it unchanged as the acceptance oracle.
1325
+ 2. Call ductape_migration_plan in read-only mode with e2e_baseline set to that passing manifest.
1326
+ 3. Present the review queue, inventory, secret NAMES, migration evidence, and low-confidence
1327
+ deterministic hints. Never present a hint as a component decision.
1328
+ 4. Use the default new-codebase mode unless the user explicitly selects in-place:
1329
+ in-place — progressively migrate the existing repository.
1330
+ new-codebase — place guidance in a separate destination while preserving the source untouched.
1331
+ It does not generate a new application; the AI creates it deliberately.
1332
+ 5. Call again with write=true only after confirming the destination. This writes guidance artifacts only.
1333
+ 6. Call with ensure_product=true when product inventory confirms the product is absent.
1334
+
1335
+ FINAL E2E ACCEPTANCE GATE
1336
+ End the migration by running the exact original E2E command against the migrated codebase while retaining
1337
+ the original checksum-bound suite. Do not silently edit, delete, skip, quarantine, or weaken baseline tests.
1338
+ Record the passing result in a value-free evidence JSON containing the command, status, evidence,
1339
+ environment, and absolute suite_root of the migrated codebase, then:
1340
+ ductape_cli("migration-e2e final --manifest <e2e-baseline.json> --evidence <final-evidence.json> --json")
1341
+ ductape_cli("migration-e2e validate --manifest <e2e-baseline.json> --strict --json")
1342
+ The final command must exactly equal the baseline command. Every suite file under suite_root must match
1343
+ its original checksum, proving the migrated codebase is tested with the same original tests and fixtures.
1344
+ New migration-specific tests supplement the baseline; they never replace it. A failing original E2E case blocks
1345
+ readiness unless the user explicitly authorizes a product behavior change and the exception is separately audited.
1346
+
1347
+ SECURITY
1348
+ Never read secret values into MCP arguments or output. Discovery reports names and locations only.
1349
+ The MCP server accepts publishable keys only and never accepts an access key.
1350
+ Secret values must be imported by the standalone CLI reading local files directly. Assets reference
1351
+ $Secret{tag}; manifests never embed credentials. Keep snd/stg/prd values separate.
1352
+ Use ductape_cli("secrets-import-env --env-file <local-file> --source-key <ENV_KEY> --key <secret-tag> --env <slug> --json").
1353
+ The command reads the value locally and redacts it from output; never place the value in an MCP argument.
1354
+ secret_references are names-only navigation evidence from Docker Compose, Kubernetes secretKeyRef,
1355
+ GitHub/GitLab/Jenkins, Spring, .NET configuration, Terraform, and AWS/GCP/Azure secret managers.
1356
+ Their value is always [NOT_READ]. Inspect context before deciding whether a reference is sensitive,
1357
+ environment-specific, shared, or suitable for a Ductape secret; never resolve it through MCP.
1358
+ Classify and reconcile every discovered reference through a value-free artifact:
1359
+ ductape_cli("migration-secrets init --analysis <analysis.json> --definition <secret-map-definition.json> --output <secret-map.json> --json")
1360
+ ductape_cli("migration-secrets validate --file <secret-map.json> --strict --json")
1361
+ Each classification requires environment, service, provider, sensitivity, rotation owner,
1362
+ Ductape secret tag, authenticated inventory action/evidence, and rotation validation/rollback.
1363
+ The validator rejects value, password, credential, private-key, and access-token fields.
1364
+ potential_secret_exposures are low-confidence security-review findings only. They contain source,
1365
+ line, category, and a truncated SHA-256 fingerprint; matched material is always [NOT_RETURNED].
1366
+ Never ask the scanner, CLI, user, or MCP to reveal a finding. Ask the user/security owner to rotate
1367
+ and remediate confirmed exposure through trusted local processes.
1368
+
1369
+ ENVIRONMENTS
1370
+ Detect environments from .env variants, deployment files, CI, Docker, Kubernetes, Terraform,
1371
+ framework configuration, and existing database/provider configuration. Normalize common aliases
1372
+ (production→prd, sandbox→snd, staging→stg) but present uncertain mappings for confirmation.
1373
+ Before creating any asset, list product environments and require complete per-environment coverage.
1374
+ Missing environments can be created idempotently through the authenticated standalone CLI:
1375
+ ductape_cli("products environments create <product-tag> -f <environment.json> --json")
1376
+ The JSON requires env_name, description, and a three-character slug. The CLI fetches first, creates only
1377
+ when absent, then fetches again to verify persistence. Update and verify with:
1378
+ ductape_cli("products environments update <product-tag> <slug> -f <patch.json> --json")
1379
+ Export authenticated inventory with ductape_cli("products environments list <product-tag> --json"),
1380
+ save it as evidence, then reconcile locally:
1381
+ ductape_cli("migration-environments --analysis <analysis.json> --inventory <inventory.json> --strict --json")
1382
+ Report matched, missing, extra, and ambiguous normalized aliases. Never guess an ambiguous mapping.
1383
+ Environment mutation is administrative CLI work and must never be routed through ductape_execute.
1384
+
1385
+ PRODUCT AND ASSET BOOTSTRAP
1386
+ Product creation is idempotent: fetch by tag, create only when absent, then link the destination.
1387
+ Use ductape_cli for products, apps, resources, cloud connections, secrets, apply, and migrations.
1388
+ Use ductape_execute only for runtime calls with a publishable key.
1389
+ For monorepos, define explicit service ownership, product boundaries, asset environment coverage,
1390
+ and environment promotion evidence:
1391
+ ductape_cli("migration-products init --analysis <analysis.json> --definition <product-map-definition.json> --output <product-map.json> --json")
1392
+ ductape_cli("migration-products validate --file <product-map.json> --strict --json")
1393
+ Every discovered workspace-unit manifest must have exactly one service owner. Each service records
1394
+ its product and target environments. Every required asset records authenticated inventory evidence
1395
+ and configured environments. Every mapped product requires promotion entry conditions, validation,
1396
+ and rollback; never assume repository, service, and product boundaries are identical.
1397
+
1398
+ DATABASE SCHEMAS AND MIGRATIONS
1399
+ For every database migration, create a definition containing baseline, data, and cutover sections:
1400
+ ductape_cli("migration-database init --definition <database-definition.json> --output <guidance-dir> --json")
1401
+ ductape_cli("migration-database validate --directory <guidance-dir> --strict --json")
1402
+ Baseline evidence covers code/live/applied schemas, drift, views/triggers/procedures/indexes/constraints,
1403
+ permissions/RLS/encryption, tenancy/sharding/partitioning, provider compatibility, IDs/timezones/collation,
1404
+ and query-performance baselines. Data planning covers transformations, batching, checkpoints, resumability,
1405
+ idempotency, PII/retention, seed data, validation and reconciliation. Cutover uses expand/backfill/
1406
+ dual-compatibility/contract phases with deployment ordering, locks, backup, tested restore, rollback,
1407
+ irreversible-change disclosure, monitoring, reconciliation, and explicit approval.
1408
+ All three artifacts require the same migration_id and database_tag. Baseline schema_snapshots cover
1409
+ code, migration, applied, live, and proposed structures with source-file SHA-256, structure hash,
1410
+ timestamp, and evidence; stale source evidence blocks readiness. structural_comparison must be matched
1411
+ or contain explicit approved differences. Data transformations require versioned source/target field
1412
+ mappings, positive batch/concurrency/memory/timeout limits, and an atomic persistent checkpoint with
1413
+ replay-test evidence. Cutover phases require unique positive order and valid prerequisite IDs.
1414
+ Inventory Prisma, TypeORM, Sequelize, Mongoose, SQL, Flyway, Liquibase, Hibernate/JPA,
1415
+ Entity Framework, golang-migrate, Goose, and other migration/schema sources.
1416
+ The planner only identifies possible schema and migration source files. It does not parse them into
1417
+ a proposed Ductape schema. The AI must inspect models, relations, indexes, constraints, migrations,
1418
+ repository behavior, tests, live/provider semantics, and applied history before proposing or writing
1419
+ ductape/database/schema.json.
1420
+ Existing migrations are recorded in migration-imports.json with order and SHA-256 checksums. Review
1421
+ their intent, then generate portable reversible files under ductape/database/migrations/<db-tag>/.
1422
+ Raw source SQL is never silently executed or wrapped because Ductape migrations deliberately use
1423
+ provider-portable operations and require honest rollback behavior.
1424
+ Preserve applied order, identifiers, indexes, constraints, defaults, nullability, and rollback semantics.
1425
+ Never mark converted migrations applied merely because source files exist. Compare live schema in snd,
1426
+ run db schema generate, inspect the diff, then db migrate --dry-run before applying.
1427
+ Composite/partial/provider-specific indexes remain explicit Ductape migration operations.
1428
+
1429
+ THIRD-PARTY APIS
1430
+ Group repeated HTTP calls by stable base host into one reusable Ductape App. Model stable operations as
1431
+ Actions with auth, headers, input mapping, output mapping, retry/timeout policy, and environment-specific
1432
+ base URLs. Prefer OpenAPI/Postman import when available. Do not create one App per call site and do not
1433
+ route internal application services through fake HTTP Apps; use Events for internal boundaries.
1434
+
1435
+ COMPONENT DECISIONS
1436
+ Databases/transactions → Ductape Database; brokers/queues → Events; object stores → Storage;
1437
+ SMTP/SMS/push/callbacks → Notifications; Redis/cache → Cache; Neo4j/Neptune/Arango/Memgraph → Graph;
1438
+ Pinecone/Qdrant/Weaviate/OpenSearch → Vector; JWT/session middleware → Sessions.
1439
+ Multi-step durable/scheduled/signal-driven work → code-first Features.
1440
+ Retries, health checks, fallbacks, quotas, circuit breakers → Resilience.
1441
+ Keep deterministic calculations, validation, domain rules, and ordinary synchronous services as code.
1442
+
1443
+ LANGUAGE RUNTIME SHAPES
1444
+ TypeScript: @ductape/sdk; NestJS uses @ductape/nestjs, @Events.Consumer, and request-scoped context.
1445
+ Go: explicit services, context.Context, cancellation, typed errors, and owned worker shutdown.
1446
+ Java: DI/Spring integration where present, executor ownership, CompletableFuture boundaries.
1447
+ .NET: DI, hosted services, async/await, CancellationToken, configuration binding.
1448
+
1449
+ SESSIONS AND DURABLE ACTORS
1450
+ Immediate user work passes the original full session token. Delayed work must not persist raw JWTs
1451
+ indefinitely; use system context or an approved delegated actor plus immutable non-secret metadata.
1452
+
1453
+ ROLLOUT
1454
+ The AI migrates one vertical slice end-to-end, test snd, introduce a feature flag/dual path where safe,
1455
+ verify idempotency, concurrency, retries, duplicate delivery, logs, and rollback, then progressively cut over.
1456
+
1457
+ AI EDITING STANDARD
1458
+ Before every edit, inspect the relevant source, dependencies, installed SDK types, configuration, tests,
1459
+ and neighboring architecture. Preserve domain behavior and public contracts unless explicitly authorized.
1460
+ Do not change or invent public or internal interfaces, method signatures, types, DTOs, event schemas,
1461
+ serialized formats, error contracts, or lifecycle contracts unless the user explicitly authorizes that
1462
+ exact change. An SDK mismatch is a finding to report and resolve, not permission to reshape application code.
1463
+ Do not assume functionality from filenames, symbols, patterns, comments, documentation, or scanner hints.
1464
+ Trace the implementation, callers, callees, tests, configuration, persisted data, and runtime effects.
1465
+ If behavior remains unclear, run or add characterization tests and record the uncertainty. Never fabricate
1466
+ behavior, compatibility, defaults, rollback guarantees, idempotency, or provider support.
1467
+ Maintain full functional parity:
1468
+ - accepted inputs, returned outputs, validation, domain results, state changes, external side effects,
1469
+ serialized data, errors, events, and user-visible behavior.
1470
+ Maintain full operational parity:
1471
+ - ordering, timing-sensitive guarantees, concurrency, transactions, retries, duplicate delivery,
1472
+ idempotency, authorization, privacy, observability, performance-sensitive behavior, startup,
1473
+ shutdown, cancellation, recovery, and degraded/failure behavior.
1474
+ Compilation and happy-path tests alone do not demonstrate parity. Use existing tests, characterization
1475
+ tests, contract tests, integration tests, failure injection, and snd smoke tests appropriate to the slice.
1476
+ If parity cannot be demonstrated, stop short of cutover and report the exact unverified behavior.
1477
+ Use Events for internal async boundaries and Apps/Actions for external APIs. Keep deterministic rules in code.
1478
+ Immediate work propagates the full session; durable work uses approved actor metadata or system context.
1479
+ Consumers are idempotent, retry ownership is singular and bounded, and external effects are not duplicated.
1480
+ After each slice: format, build, test, rescan, reconcile assets through ductape_cli, smoke-test in snd,
1481
+ and report unresolved findings. A clean scanner result alone never proves a correct migration.
1482
+
1483
+ CONTEXTUAL FILE REVIEW PROTOCOL
1484
+ Use review_queue as a coverage aid. Review relevant files individually, starting with repository
1485
+ instructions, manifests, entrypoints, configuration, dependency injection, tests, and deployment files.
1486
+ For each file record: purpose; imports/dependencies; callers/callees; configuration and secret-name
1487
+ references; interfaces/types/signatures/DTOs/event schemas/serialized contracts; database behavior;
1488
+ events/background work; external APIs; sessions/authorization;
1489
+ cache/storage/notifications/graph/vector use; failure policy; tests/invariants; and follow-up files.
1490
+ Follow wrappers and references until the actual external effect and domain intent are understood.
1491
+ Classify each ledger finding:
1492
+ observed — directly supported by source/configuration
1493
+ inferred — likely, but requires more context
1494
+ proposed — possible Ductape design, not yet approved
1495
+ confirmed — verified through source, installed SDK types, tests, inventory, or user confirmation
1496
+ Do not claim coverage until every relevant queue item is reviewed or excluded with a written reason.
1497
+ Do not read .env secret values into MCP context: record names only and use standalone CLI import.
1498
+
1499
+ AUDITABLE REVIEW LEDGER
1500
+ After write=true creates migration-guidance/analysis.json, initialize the ledger:
1501
+ ductape_cli("migration-review init --analysis <path>/analysis.json --json")
1502
+ Record contextual evidence through a validated JSON input file:
1503
+ ductape_cli("migration-review record --ledger <ledger> --file <relative-file> --data <evidence.json> --json")
1504
+ The evidence file may contain purpose, dependencies, follow_up_files, interfaces, findings, and
1505
+ references. Reference kinds are import | caller | callee | implements | event | test | config | schema.
1506
+ Every finding requires location: { start_line, end_line } with positive, ordered source lines.
1507
+ Every finding also requires symbol: { kind, name, qualified_name? } so evidence identifies the
1508
+ affected module/class/interface/function/method/field/route/event/schema rather than only a filename.
1509
+ Internal references must point to reviewed/excluded ledger files before readiness.
1510
+ Add a newly discovered repository file without dropping review coverage:
1511
+ ductape_cli("migration-review follow-up --ledger <ledger> --file <source> --follow-up <target> --json")
1512
+ Record parity with structured validation:
1513
+ ductape_cli("migration-review parity --ledger <ledger> --file <file> --concern interface --status verified --evidence <evidence> --json")
1514
+ ductape_cli("migration-review parity --ledger <ledger> --file <file> --concern functional --status verified --evidence <evidence> --json")
1515
+ ductape_cli("migration-review parity --ledger <ledger> --file <file> --concern operational --status verified --evidence <evidence> --json")
1516
+ For a genuine not-applicable concern, use --status not_applicable --reason <reason>.
1517
+ For each entry the ledger records purpose, dependencies, follow-up files, references, interfaces,
1518
+ findings, exclusion metadata where applicable, and:
1519
+ interface_parity, functional_parity, operational_parity
1520
+ Each parity status is pending | verified | not_applicable.
1521
+ verified requires concrete evidence. not_applicable requires a reason.
1522
+ After completing a file, snapshot the exact reviewed content:
1523
+ ductape_cli("migration-review snapshot --ledger <path>/review-ledger.json --file <relative-file> --json")
1524
+ A later checksum change makes that review stale. Follow-up files must also exist in the ledger;
1525
+ never silently omit a referenced file. Reopen a review explicitly when needed:
1526
+ ductape_cli("migration-review reopen --ledger <ledger> --file <relative-file> --json")
1527
+ Exclude only with a classification and reason:
1528
+ ductape_cli("migration-review exclude --ledger <ledger> --file <file> --classification <type> --reason <reason> --json")
1529
+ Types: generated | vendor | build | snapshot | other. Generated exclusions additionally require
1530
+ --generator and --regeneration-test so generated contracts are not silently ignored.
1531
+ If a reviewed file disappears, validation reports checksum-matched probable_moves without changing
1532
+ history. Accept a verified move only when content is identical:
1533
+ ductape_cli("migration-review move --ledger <ledger> --from <old-file> --to <new-file> --json")
1534
+ A stale file transitively invalidates reviewed entries that reference it through internal references,
1535
+ follow-up files, or finding follow-ups. Re-review the dependency chain before readiness.
1536
+ Every structured ledger mutation uses an exclusive lock, checks the expected revision, appends an
1537
+ actor/tool/version/timestamp operation event, chains it to the previous SHA-256 hash, and binds the
1538
+ newest event to the current ledger-entry state. Never edit review-ledger.json directly after audit
1539
+ events exist: validation treats that as tampering. A concurrent conflict must be retried after re-reading
1540
+ the latest ledger; never overwrite another reviewer.
1541
+ For parallel branches, merge only against an explicit common base:
1542
+ ductape_cli("migration-review merge --base <base.json> --current <current.json> --incoming <incoming.json> --output <merged.json> --json")
1543
+ Non-overlapping file reviews merge into a new ledger; divergent edits to the same file return conflicts
1544
+ and never overwrite either input. For trusted release attestation, sign outside MCP with a protected
1545
+ Ed25519 private-key file and verify using the independently distributed public key:
1546
+ ductape_cli("migration-review sign --ledger <ledger> --private-key <private.pem> --key-id <identity> --json")
1547
+ ductape_cli("migration-review verify-signature --ledger <ledger> --signature <ledger.sig.json> --public-key <public.pem> --json")
1548
+ Never pass private-key contents through MCP or prompts.
1549
+ Check progress without claiming readiness:
1550
+ ductape_cli("migration-review validate --ledger <path>/review-ledger.json --json")
1551
+ Before proposing cutover, require strict validation:
1552
+ ductape_cli("migration-review validate --ledger <path>/review-ledger.json --strict --json")
1553
+ Strict readiness requires no pending or stale files, reasoned exclusions, complete follow-ups,
1554
+ covered internal references, recorded file purpose, and verified or reasoned-not-applicable
1555
+ interface/functional/operational parity.
1556
+
1557
+ GENERATED, VENDORED, AND SNAPSHOT CONTRACTS
1558
+ Scanner generated_source_hints are navigation evidence, never permission to ignore a file. Contextually
1559
+ classify every hint and any discovered generated or vendored file in a definition, then:
1560
+ ductape_cli("migration-generated init --analysis <analysis.json> --definition <generated-vendor-definition.json> --json")
1561
+ ductape_cli("migration-generated validate --file <generated-vendor-evidence.json> --strict --json")
1562
+ For generated files record contract_kind (public_api | generated_client | schema | ui_snapshot | internal),
1563
+ owner, generator name/version/command, repository-relative generator inputs, passing clean-workspace
1564
+ regeneration evidence, the regenerated output file, and compatibility_tests. The CLI records SHA-256
1565
+ input/checked-in/regenerated checksums and compares output; it never executes an arbitrary generator command.
1566
+ public_api, generated_client, schema, and ui_snapshot are contracts and require compatibility tests.
1567
+ A clean-regenerated mismatch or changed generator input blocks readiness.
1568
+ For vendored source record upstream source/version/SHA-256 checksum, owner, locally_modified, diff_evidence,
1569
+ and compatibility tests. The validator derives modification from current versus upstream checksum; it rejects
1570
+ a false classification, and locally modified vendor source requires owned diff evidence.
1571
+ Never overwrite or normalize checked-in generated/vendor output to make validation pass. Re-run the real
1572
+ generator in an isolated clean workspace using normal development tools, inspect the diff, and record evidence.
1573
+
1574
+ REPOSITORY-WIDE ASSURANCE MATRIX
1575
+ Create a version:1, artifact_kind:"ductape_migration_assurance" JSON artifact and validate it with:
1576
+ ductape_cli("migration-assurance --file <assurance.json> --strict --json")
1577
+ This is an evidence gate, not a test runner. The AI runs the referenced tests with normal development tools.
1578
+ It requires tested session flows from frontend through backend, Events, Features, and scheduled work, including
1579
+ refresh, revocation, logout, account switching, expiry, and actor-audit evidence that is not authorization.
1580
+ It requires Feature duplicate-delivery, signal, compensation, restart, layered retry-budget, fallback, quota,
1581
+ and health-check evidence.
1582
+ Every third_party_calls entry records the inspected wrapper chain and client family (Axios, Fetch, Java, .NET,
1583
+ Go, GraphQL, gRPC, or generated), base URL, auth, headers, timeout, retries, pagination, rate limits, normalized
1584
+ errors, webhook/replay behavior, parity evidence, and tests.
1585
+ Component matrices require:
1586
+ graph — schema, edges, indexes, traversal, reconciliation
1587
+ vector — dimensions, metric, embedding version, metadata schema, batching, quality
1588
+ storage — object keys, metadata, ACL, encryption, retention, multipart, checksums
1589
+ cache — keys, TTL, invalidation, stampede, consistency, fallback
1590
+ notifications — templates, channels, providers, suppression, retry, delivery, privacy
1591
+ analytics — event schema, identity, consent, masking, delivery, dashboard parity
1592
+ Provider migrations require tested resumability evidence.
1593
+ Runtime evidence covers safe procedures for TypeScript, Go, Java, and .NET; request/query/Event/Feature/external
1594
+ effect correlation; trace/log compatibility; load/concurrency/retry/duplicate delivery; lifecycle/restart;
1595
+ redaction; dashboards and alert thresholds.
1596
+ The sdk_matrix requires each supported language's exact package/version, installed capability evidence,
1597
+ equivalent parity tests, lifecycle and error-mapping requirements, examples, anti-patterns, and an explicit
1598
+ block/escalate policy for unsupported capabilities. Never silently emulate a missing SDK capability.
1599
+
1600
+ COMPREHENSIVE VERIFICATION MATRIX
1601
+ Record automation that the AI actually ran with normal project tools in a version:1,
1602
+ artifact_kind:"ductape_migration_verification_matrix" file, then:
1603
+ ductape_cli("migration-verification --file <verification-matrix.json> --strict --json")
1604
+ This command validates evidence; it never executes the recorded commands. Every one of 63 requirements
1605
+ must be passed and include tests, structured details, automation tool/command/result/environment, and
1606
+ source citations containing absolute repository, relative file, exact line range, and current SHA-256.
1607
+ A changed or missing cited file invalidates readiness.
1608
+ Categories cover multi-repository summaries/checkpoints/contracts; normalized before/after parity,
1609
+ nondeterminism, test strength, mutation and safe shadow signals; frontend browser/accessibility/visual/
1610
+ performance/security/mobile evidence; complete database modeling, data movement and cutover drills;
1611
+ component asset design/inventory/environment/provider/payload/dependency evidence; and contextual
1612
+ third-party client and App/Action designs.
1613
+ Dependency records require nodes, edges, and an evidenced order. Before/after records require explicit
1614
+ normalization and comparison. Nondeterminism requires named fields and approved differences. Visual,
1615
+ irreversible, and residual-uncertainty decisions require actor, authority, and approval evidence.
1616
+ Never manufacture an automation result or approval to satisfy the matrix. A blocked or failed record
1617
+ remains a blocker and must be reported as residual risk.
1618
+
1619
+ DEPENDENCY-AWARE LARGE-REPOSITORY PROPOSAL
1620
+ After contextual references exist in the review ledger, generate a non-authoritative proposal:
1621
+ ductape_cli("migration-portfolio propose --ledger <ledger> --max-bytes <bytes> --max-tokens <tokens> --json")
1622
+ The proposer builds the internal reference graph, condenses strongly connected components so cyclic files
1623
+ stay together, topologically orders dependencies before consumers, and records byte plus ceil(bytes/4)
1624
+ token estimates. An indivisible SCC over either configured limit is marked oversized_scc for human/AI
1625
+ review; it is never split unsafely. The output authority is advisory_only and must be contextually reviewed
1626
+ before it becomes a portfolio definition.
1627
+ Verification-matrix records may declare details.depends_on using category.requirement identifiers. A stale
1628
+ cited dependency transitively invalidates dependent service/package summaries and readiness.
1629
+
1630
+ PARITY-GATED MIGRATION SLICES
1631
+ Create a JSON array containing the reviewed repository-relative files for one vertical slice, then:
1632
+ ductape_cli("migration-slice init --ledger <ledger> --tag <tag> --name <name> --files <files.json> --json")
1633
+ Complete the generated slice manifest with:
1634
+ product_boundary, sdk_capabilities,
1635
+ interface_contracts, functional_requirements, operational_requirements,
1636
+ required_assets, tests, failure_tests, runtime_evidence, smoke_checks,
1637
+ cutover_conditions, rollback_conditions, deployment_cutover.
1638
+ Apply those fields through a validated definition JSON file:
1639
+ ductape_cli("migration-slice define --slice <slice.json> --data <definition.json> --json")
1640
+ Each required asset records kind, tag, action (reuse | create | update | blocked), and inventory_evidence.
1641
+ Inventory evidence must come from ductape_cli administrative inventory, never an assumed asset.
1642
+ product_boundary records product_tag, included services, target environments, and repository/inventory
1643
+ evidence. Never assume one repository equals one service or one Ductape product.
1644
+ sdk_capabilities records language, installed package, exact version, capability, and evidence from
1645
+ installed exports/types or version-matched primary documentation. Never assume cross-language parity.
1646
+ runtime_evidence and failure_tests cover behavior static review cannot prove: external effects,
1647
+ transactions, ordering, concurrency, retry/duplicate delivery, startup/shutdown, and degraded behavior.
1648
+ deployment_cutover records the implementation commit, per-environment deployed versions, feature-flag/
1649
+ dual-run/traffic state, explicit no-return points and mitigations, a timed observation window with success
1650
+ thresholds, dashboard/alert evidence, and a passing executed rollback rehearsal. Unrecorded deployment
1651
+ state or an untested rollback blocks strict readiness.
1652
+ Validate during work:
1653
+ ductape_cli("migration-slice validate --slice <slice.json> --json")
1654
+ Gate cutover:
1655
+ ductape_cli("migration-slice validate --slice <slice.json> --strict --json")
1656
+ A slice cannot be ready with stale/unreviewed files, incomplete parity, missing tests/smoke checks,
1657
+ missing failure/runtime evidence, an unproven product boundary or SDK capability, missing cutover or
1658
+ rollback conditions, incomplete asset evidence, or blocked reconciliation.
1659
+
1660
+ LARGE CODEBASES AND CONTEXT BOUNDARIES
1661
+ Never load a huge repository into one model context or rely on conversational memory for coverage.
1662
+ Partition reviewed files into bounded, non-overlapping groups with an explicit context_budget,
1663
+ durable summary, and file-checksum provenance. Define partitions, slice paths, and cross-slice contracts:
1664
+ ductape_cli("migration-portfolio init --ledger <ledger> --definition <portfolio-definition.json> --json")
1665
+ The CLI computes provenance checksums; changed files stale the affected partition summary.
1666
+ Validate resumable repository-wide coverage:
1667
+ ductape_cli("migration-portfolio validate --portfolio <portfolio.json> --json")
1668
+ Gate repository cutover:
1669
+ ductape_cli("migration-portfolio validate --portfolio <portfolio.json> --strict --json")
1670
+ Strict portfolio validation requires every ledger file in exactly one partition, current provenance,
1671
+ every slice ready, and evidenced provider/consumer cross-slice contracts. Summaries are navigation
1672
+ aids only; reopen source review whenever provenance becomes stale.
1673
+
1674
+ FRONTEND MIGRATION PARITY
1675
+ Mark frontend slices with surfaces: ["frontend"] (or include backend/worker for a mixed slice).
1676
+ Frontend strict readiness requires evidence for routes/navigation, rendered loading/empty/error/success
1677
+ states, forms/validation, accessibility, responsive behavior, browser storage, authentication transitions,
1678
+ SSR/hydration, realtime reconnect/resubscription, analytics/privacy, performance budgets,
1679
+ visual regression, and cross-browser behavior.
1680
+ Inspect installed @ductape/client, @ductape/react, or @ductape/vue exports before editing. Preserve UI
1681
+ contracts and application state semantics; do not replace domain state with analytics. Verify full-session
1682
+ identify/clearSession lifecycle, route pageviews, privacy masking, hidden-state exclusion, trace correlation,
1683
+ unsubscribe/teardown, reconnect duplication, SSR browser boundaries, and accessibility behavior.
1684
+
1685
+ PARITY CLAIMS
1686
+ Never promise or report "100% parity" merely because gates pass. The gates require the strongest available
1687
+ evidence and make unverified behavior explicit; arbitrary software cannot receive a mathematical parity
1688
+ guarantee from static review and finite tests. Each slice records before/after evidence from appropriate
1689
+ characterization, contract, golden, side-effect, database-state, event-order, failure-injection,
1690
+ load/concurrency, or safe shadow-comparison checks. Report residual uncertainty honestly.
1691
+ `.trim(),
1253
1692
  frontend: `
1254
1693
  DUCTAPE FRONTEND SDK GUIDE
1255
1694
 
@@ -3764,7 +4203,15 @@ async function main() {
3764
4203
  }
3765
4204
  const firstWord = args.command.trim().split(/\s+/)[0];
3766
4205
  const isAuthCommand = firstWord === 'login' || firstWord === 'logout';
3767
- if (!isAuthCommand) {
4206
+ const isLocalMigrationGuidance = (firstWord === 'migrate-codebase' && !args.command.includes('--ensure-product')) ||
4207
+ firstWord === 'migration-review' ||
4208
+ firstWord === 'migration-slice' ||
4209
+ firstWord === 'migration-portfolio' ||
4210
+ firstWord === 'migration-database' ||
4211
+ firstWord === 'migration-environments' ||
4212
+ firstWord === 'migration-products' ||
4213
+ firstWord === 'migration-secrets';
4214
+ if (!isAuthCommand && !isLocalMigrationGuidance) {
3768
4215
  // Cache successful authentication, but re-check a missing/expired session on every call.
3769
4216
  // The user may complete `ductape login` in another terminal while this MCP process remains
3770
4217
  // alive; caching "none" would otherwise make the MCP blind to the newly written session.
@@ -3814,6 +4261,31 @@ async function main() {
3814
4261
  ...(result.success ? {} : { isError: true }),
3815
4262
  };
3816
4263
  };
4264
+ const migrationHandler = async (args) => {
4265
+ if (args.mode === 'new-codebase' && !args.destination) {
4266
+ return {
4267
+ content: [{ type: 'text', text: 'Error: destination is required for new-codebase mode.' }],
4268
+ isError: true,
4269
+ };
4270
+ }
4271
+ const command = [
4272
+ 'migrate-codebase',
4273
+ '--source', shellArgument(args.source),
4274
+ '--e2e-baseline', shellArgument(args.e2e_baseline),
4275
+ '--mode', args.mode,
4276
+ ...(args.destination ? ['--destination', shellArgument(args.destination)] : []),
4277
+ ...(args.product ? ['--product', shellArgument(args.product)] : []),
4278
+ ...(args.name ? ['--name', shellArgument(args.name)] : []),
4279
+ ...(args.database ? ['--database', shellArgument(args.database)] : []),
4280
+ '--max-file-bytes', String(args.max_file_bytes),
4281
+ ...(args.include.length ? ['--include', shellArgument(args.include.join(','))] : []),
4282
+ ...(args.exclude.length ? ['--exclude', shellArgument(args.exclude.join(','))] : []),
4283
+ ...(args.ensure_product ? ['--ensure-product'] : []),
4284
+ ...(args.write ? ['--write'] : []),
4285
+ '--json',
4286
+ ].join(' ');
4287
+ return cliHandler({ command });
4288
+ };
3817
4289
  const executeHandler = async (args) => {
3818
4290
  try {
3819
4291
  const runtimeMutationMethods = {
@@ -3834,7 +4306,8 @@ async function main() {
3834
4306
  }
3835
4307
  const key = args.publishable_key || process.env.DUCTAPE_PUBLISHABLE_KEY;
3836
4308
  if (!key) {
3837
- throw new Error('Not authenticated. Set DUCTAPE_PUBLISHABLE_KEY in your MCP server env config, or pass publishable_key on every tool call.');
4309
+ throw new Error('Runtime authentication is missing. Set DUCTAPE_PUBLISHABLE_KEY in the MCP server environment ' +
4310
+ 'or pass publishable_key to ductape_execute. The MCP server never accepts access keys.');
3838
4311
  }
3839
4312
  // The TS SDK uses ductape.events.* for broker operations; the backend proxy uses messageBrokers.
3840
4313
  const proxyModule = args.module === 'events' ? 'messageBrokers' : args.module;
@@ -3857,7 +4330,18 @@ async function main() {
3857
4330
  return p;
3858
4331
  });
3859
4332
  }
3860
- const result = await executeViaProxy(key, proxyModule, args.method, params);
4333
+ let result;
4334
+ try {
4335
+ result = await executeViaProxy(key, proxyModule, args.method, params);
4336
+ }
4337
+ catch (error) {
4338
+ const message = error instanceof Error ? error.message : String(error);
4339
+ if (/authentication failed|unauthorized|invalid.*key/i.test(message)) {
4340
+ throw new Error('The DUCTAPE_PUBLISHABLE_KEY was rejected by the runtime proxy. ' +
4341
+ 'Use a publishable key for the same workspace/product. The MCP server never accepts or forwards access keys.');
4342
+ }
4343
+ throw error;
4344
+ }
3861
4345
  return { content: [{ type: 'text', text: JSON.stringify(result ?? null, null, 2) }] };
3862
4346
  }
3863
4347
  catch (err) {
@@ -3989,9 +4473,18 @@ async function main() {
3989
4473
  'index strategy, operation types) that should be confirmed with the user first.\n\n' +
3990
4474
  'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
3991
4475
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
3992
- 'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue',
4476
+ 'notifications, resilience, features, events, logs, migration, frontend, frontend-analytics, client, react, vue',
3993
4477
  inputSchema: docsInputSchema,
3994
4478
  }, docsHandler);
4479
+ server.registerTool('ductape_migration_plan', {
4480
+ title: 'Ductape AI Migration Guidance',
4481
+ description: 'Inspect a TypeScript, Go, Java, or .NET repository without exposing secret values. ' +
4482
+ 'Builds a relevant-file review queue, secret-name inventory, checksummed migration evidence, and low-confidence navigation hints. ' +
4483
+ 'The AI must review files contextually and maintain an evidence ledger before proposing components or schemas. ' +
4484
+ 'It never generates or rewrites application code or executable assets. ' +
4485
+ 'Supports in-place and new-codebase guidance destinations. Read-only unless write or ensure_product is explicitly enabled.',
4486
+ inputSchema: migrationInputSchema,
4487
+ }, migrationHandler);
3995
4488
  server.registerTool('ductape_cli', {
3996
4489
  title: 'Ductape CLI',
3997
4490
  description: 'Run a Ductape CLI command for administrative operations.\n\n' +
@@ -4101,6 +4594,7 @@ async function main() {
4101
4594
  server.tool('ductape_generate_snippet', snippetGenerateInputSchema.shape, snippetGenerateHandler);
4102
4595
  server.tool('ductape_schema', schemaInputSchema.shape, schemaHandler);
4103
4596
  server.tool('ductape_docs', docsInputSchema.shape, docsHandler);
4597
+ server.tool('ductape_migration_plan', migrationInputSchema.shape, migrationHandler);
4104
4598
  server.tool('ductape_cli', cliInputSchema.shape, cliHandler);
4105
4599
  }
4106
4600
  else {