@ductape/mcp 0.2.30 → 0.2.31

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
@@ -6,6 +6,7 @@
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ - Added `cli-authentication` guidance for automatic Google/GitHub browser OAuth, validated loopback callbacks, trusted-terminal handoff, credential non-disclosure, and external session refresh.
9
10
  - Added source-verified graph/vector projection guidance to the `features`, `events`, `graphs`, and `vector` docs topics, including exact graph/vector payloads, NestJS consumer routing, replay/idempotency, projection-state ordering, rebuild/drift repair, and an explicit stop condition for the currently missing code-first `ctx.vector` API.
10
11
  - Added read-only `ductape_events_topic_setup` and `ductape_events_validate_project` tools and made the canonical one-topic-per-file `ductape/events/<topic-tag>.topic.json` layout explicit and enforceable through the CLI.
11
12
  - Mark `ductape_function_setup` as read-only, non-destructive, idempotent, and closed-world in both MCP registration APIs so hosts do not incorrectly require mutation approval for its pure setup-plan generation.
package/dist/index.js CHANGED
@@ -909,12 +909,13 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
909
909
  vector.deleteIndex [{ product, env, vector, name }]
910
910
  vector.listIndexes [{ product, env, vector }]
911
911
  vector.count [{ product, env, vector, namespace? }]
912
- vector.actions.create [{ product, vector, actionTag, name, operation, template, description?, parameters? }]
913
- vector.actions.update [{ product, vector, actionTag, name?, description?, template?, parameters? }]
914
- vector.actions.fetch [{ product, vector, actionTag }]
915
- vector.actions.fetchAll [{ product, vector }]
916
- vector.actions.delete [{ product, vector, actionTag }]
917
- vector.actions.execute [{ product, env, vector, action, input }]
912
+ vector.action.create [{ product, vector, actionTag, name, operation, template, description?, parameters? }]
913
+ vector.action.update [{ product, vector, actionTag, name?, description?, template?, parameters? }]
914
+ vector.action.fetch [{ product, vector, actionTag }]
915
+ vector.action.fetchAll [{ product, vector }]
916
+ vector.action.delete [{ product, vector, actionTag }]
917
+ vector.action.execute [{ product, env, vector, action, input, session? }]
918
+ ← synchronous saved-action execution. Do not use vector.query for a saved action.
918
919
 
919
920
  ━━━ MODULE: features ━━━
920
921
  Feature definitions are code-first. Use features.define in application source; do not call
@@ -1500,6 +1501,7 @@ function runCli(command) {
1500
1501
  'or use an OAuth flow:',
1501
1502
  ' ductape login --browser google',
1502
1503
  ' ductape login --browser github',
1504
+ 'Browser OAuth returns to the CLI automatically through a validated 127.0.0.1 callback.',
1503
1505
  '',
1504
1506
  'Do not paste a password, OAuth callback token, or stored CLI credential into an agent prompt.',
1505
1507
  'After login succeeds, retry the same ductape_cli command.',
@@ -1551,7 +1553,7 @@ const docsInputSchema = z.object({
1551
1553
  topic: z.string().describe('Feature topic to look up. Supported: ' +
1552
1554
  'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
1553
1555
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
1554
- 'notifications, resilience, features, portable-functions, events, logs, migration, frontend, frontend-analytics, client, react, vue'),
1556
+ 'notifications, resilience, features, portable-functions, events, logs, migration, cli-authentication, frontend, frontend-analytics, client, react, vue'),
1555
1557
  });
1556
1558
  const eventsDiscoveryInputSchema = z.object({
1557
1559
  query: z.string().optional().describe('Capability or recovery search, including DLQ, dead letter, failed messages, retry, poison message, replay, or consumer failure.'),
@@ -1607,6 +1609,34 @@ const migrationInputSchema = z.object({
1607
1609
  write: z.boolean().optional().default(false).describe('Write redacted advisory artifacts only. This never writes application code or executable Ductape assets.'),
1608
1610
  });
1609
1611
  const DOCS = {
1612
+ 'cli-authentication': `
1613
+ DUCTAPE CLI AUTHENTICATION
1614
+
1615
+ For an interactive local login, prefer browser OAuth:
1616
+ ductape login --browser google
1617
+ ductape login --browser github
1618
+
1619
+ The CLI opens the provider in the user's browser, starts a temporary loopback listener on
1620
+ 127.0.0.1, validates the returned OAuth state, exchanges the callback token, stores the resulting
1621
+ session in the local Ductape credential store, and then continues workspace selection. The user
1622
+ does not copy a callback token or share credentials with an agent.
1623
+
1624
+ Run browser login only in the user's trusted local terminal. An MCP tool, agent subprocess, CI
1625
+ runner, container, SSH session, or remote development host may not own the browser's loopback
1626
+ interface. Do not invoke interactive login through ductape_cli and do not ask the user to paste a
1627
+ password, OAuth callback token, auth token, or stored credential into chat.
1628
+
1629
+ Use email/password login only when the user deliberately chooses it in their own terminal:
1630
+ ductape login
1631
+
1632
+ Use --token only as a compatibility or automation fallback when the user already possesses a
1633
+ valid OAuth callback token through a trusted flow. Never solicit that token in an agent prompt.
1634
+
1635
+ After login succeeds, retry the original ductape_cli operation. The MCP re-reads a previously
1636
+ missing or expired external CLI session without requiring an MCP restart. If a command returns
1637
+ HTTP 401 while workspace reads still succeed, treat it as endpoint authorization or command
1638
+ routing failure, not as a reason to re-authenticate.
1639
+ `.trim(),
1610
1640
  'portable-functions': `
1611
1641
  PORTABLE APPLICATION FUNCTIONS
1612
1642
 
@@ -2551,10 +2581,12 @@ Schema management:
2551
2581
  graph.dropIndex / dropConstraint / listIndexes / listConstraints
2552
2582
 
2553
2583
  Saved actions (parameterized queries stored on the product):
2554
- graph.createAction [{ graphTag?, name, description?, operation, query, parameters: [{ name, type, required?, defaultValue?, description? }] }, productTag?]
2555
- graph.listActions [graphTag?, productTag?]
2556
- graph.execute [{ product, env, graph, action, input?, session?, cache? }]
2557
- graph.dispatch [data] ← call ductape_generate_payload FIRST
2584
+ graph.action.create [{ product, graph|graphTag, name, description?, operation, query, parameters? }]
2585
+ graph.action.fetchAll [{ product, graph|graphTag }]
2586
+ graph.action.fetch [{ product, graph|graphTag, action|actionTag }]
2587
+ graph.action.execute [{ product, env, graph, action, input, session? }]
2588
+ graph.action.dispatch [{ product, env, graph, event, input, schedule? }] ← call ductape_generate_payload FIRST
2589
+ Use graph.action.execute for a saved action. graph.query is only for a direct provider-native query.
2558
2590
 
2559
2591
  Supported index types: btree | fulltext | vector | range | point | text
2560
2592
  Supported constraint types: UNIQUE | EXISTS | NODE_KEY
@@ -4025,6 +4057,14 @@ When you call features.define({ handler }), the handler runs TWICE:
4025
4057
  For loops: supply recordInput and iterate ctx.sampleInput so all iterations are recorded.
4026
4058
  ctx.input is always the runtime operator surface and must never expose recordInput literals.
4027
4059
  For branches: use branchOverrides so each path is captured.
4060
+ Never make an authorization, validation, tenancy, or other security decision by branching on
4061
+ ctx.input during recording. Use ctx.sampleInput only to discover graph shape; enforce security
4062
+ invariants inside a runtime portable Function or recorded step.
4063
+
4064
+ ductape features sync [filter] sets DUCTAPE_SYNC_MODE=1 and, when filtered,
4065
+ DUCTAPE_FEATURE_FILTER=<filter>. This is an administrative catalogue-only lifecycle: framework
4066
+ integrations and project readiness hooks must not start HTTP listeners, provider probes,
4067
+ schedulers, or Event consumers. Apply the filter before booting unrelated service modules.
4028
4068
 
4029
4069
  2. EXECUTION PHASE (at runtime) — handler is called with a real ExecutionContext.
4030
4070
  ctx.step() actually executes. All real Ductape component calls happen.
@@ -5100,8 +5140,10 @@ EXACT CODE-FIRST VECTOR CONTEXT:
5100
5140
  ductape vector actions get <action-tag> --vector <vector-tag> --json
5101
5141
  Always list and inspect first. Reuse an existing action when operation, namespace/filter/template,
5102
5142
  parameters, and output semantics match; do not create a duplicate action under a new name.
5103
- Update/delete/list use the same \`ductape vector actions\` surface. At runtime the SDK namespace is
5104
- \`ductape.vector.actions.*\` (plural), while Feature reuse is singular \`ctx.vector.execute(...)\`.
5143
+ Update/delete/list use the same plural \`ductape vector actions\` CLI surface. Runtime SDK/MCP calls
5144
+ use the singular \`ductape.vector.action.*\` namespace; execute saved actions with
5145
+ \`ductape.vector.action.execute({ product, env, vector, action, input })\`. Feature handlers instead
5146
+ use \`ctx.vector.execute({ vector, action, input })\` because product/env/session are inherited.
5105
5147
  Vertex AI Vector Search stores and searches supplied vectors. It does NOT generate embeddings.
5106
5148
  Do not claim that a Vertex Vector Search index embeds text.
5107
5149
 
@@ -5461,7 +5503,9 @@ const cliInputSchema = z.object({
5461
5503
  '"features sync" (runs the project\'s own "features:sync" npm script) — never call ' +
5462
5504
  'features.define from the app\'s normal startup path, since that blocks every boot on ' +
5463
5505
  'Ductape API reachability. See ductape_docs for the full convention.\n\n' +
5464
- 'The CLI uses the user\'s local logged-in session (ductape login) no key is required.'),
5506
+ 'The CLI uses the user\'s local logged-in session. Prefer browser OAuth in a trusted local terminal: ' +
5507
+ 'ductape login --browser google (or github). It returns automatically through a validated loopback callback. ' +
5508
+ 'Never invoke interactive login through MCP or ask the user for credentials.'),
5465
5509
  });
5466
5510
  async function loadMcpSdk() {
5467
5511
  try {
@@ -5626,6 +5670,25 @@ async function main() {
5626
5670
  const isLocalMigrationGuidance = (firstWord === 'migrate-codebase' && !args.command.includes('--ensure-product')) ||
5627
5671
  firstWord.startsWith('migration-');
5628
5672
  const isDiagnostic = firstWord === 'doctor';
5673
+ if (firstWord === 'login') {
5674
+ return {
5675
+ content: [{
5676
+ type: 'text',
5677
+ text: [
5678
+ 'Ductape login must be completed by the user in a trusted local terminal, not through an MCP tool process.',
5679
+ '',
5680
+ 'Preferred browser OAuth:',
5681
+ ' ductape login --browser google',
5682
+ ' ductape login --browser github',
5683
+ '',
5684
+ 'The browser returns to the CLI automatically through a validated 127.0.0.1 callback; no token copying is required.',
5685
+ 'Never ask the user to paste a password, OAuth callback token, auth token, or stored CLI credential into the agent.',
5686
+ 'After login succeeds, retry the original ductape_cli operation. The MCP will detect the new session.',
5687
+ ].join('\n'),
5688
+ }],
5689
+ isError: true,
5690
+ };
5691
+ }
5629
5692
  if (!isAuthCommand && !isLocalMigrationGuidance && !isDiagnostic) {
5630
5693
  // Cache successful authentication, but re-check a missing/expired session on every call.
5631
5694
  // The user may complete `ductape login` in another terminal while this MCP process remains
@@ -5648,6 +5711,7 @@ async function main() {
5648
5711
  'or:',
5649
5712
  ` ductape login --browser google${wsFlag}`,
5650
5713
  ` ductape login --browser github${wsFlag}`,
5714
+ 'Browser OAuth returns to the CLI automatically through a validated 127.0.0.1 callback.',
5651
5715
  '',
5652
5716
  'Never ask the user to paste their password, OAuth callback token, or stored CLI credential into the agent.',
5653
5717
  'After login succeeds, retry the original ductape_cli command.',
@@ -6082,7 +6146,7 @@ async function main() {
6082
6146
  'index strategy, operation types) that should be confirmed with the user first.\n\n' +
6083
6147
  'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
6084
6148
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
6085
- 'notifications, resilience, features, portable-functions, events, logs, migration, frontend, frontend-analytics, client, react, vue',
6149
+ 'notifications, resilience, features, portable-functions, events, logs, migration, cli-authentication, frontend, frontend-analytics, client, react, vue',
6086
6150
  inputSchema: docsInputSchema,
6087
6151
  }, docsHandler);
6088
6152
  server.registerTool('ductape_events_discover', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.2.30",
3
+ "version": "0.2.31",
4
4
  "description": "MCP server that exposes Ductape SDK operations via the backend proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",