@jaypie/mcp 0.3.2 → 0.4.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.
Files changed (79) hide show
  1. package/dist/createMcpServer.d.ts +7 -1
  2. package/dist/index.js +26 -3135
  3. package/dist/index.js.map +1 -1
  4. package/dist/suite.d.ts +1 -0
  5. package/dist/suite.js +2442 -0
  6. package/dist/suite.js.map +1 -0
  7. package/package.json +8 -3
  8. package/release-notes/constructs/1.2.17.md +11 -0
  9. package/release-notes/fabric/0.1.2.md +11 -0
  10. package/release-notes/fabric/0.1.3.md +25 -0
  11. package/release-notes/fabric/0.1.4.md +42 -0
  12. package/release-notes/mcp/0.3.3.md +12 -0
  13. package/release-notes/mcp/0.3.4.md +36 -0
  14. package/release-notes/mcp/0.4.0.md +27 -0
  15. package/release-notes/testkit/1.2.15.md +23 -0
  16. package/skills/agents.md +25 -0
  17. package/skills/aws.md +107 -0
  18. package/skills/cdk.md +141 -0
  19. package/skills/cicd.md +152 -0
  20. package/skills/datadog.md +129 -0
  21. package/skills/debugging.md +148 -0
  22. package/skills/dns.md +134 -0
  23. package/skills/dynamodb.md +140 -0
  24. package/skills/errors.md +142 -0
  25. package/skills/fabric.md +191 -0
  26. package/skills/index.md +7 -0
  27. package/skills/jaypie.md +100 -0
  28. package/skills/legacy.md +97 -0
  29. package/skills/logs.md +160 -0
  30. package/skills/mocks.md +174 -0
  31. package/skills/models.md +195 -0
  32. package/skills/releasenotes.md +94 -0
  33. package/skills/secrets.md +155 -0
  34. package/skills/services.md +175 -0
  35. package/skills/style.md +190 -0
  36. package/skills/tests.md +209 -0
  37. package/skills/tools.md +127 -0
  38. package/skills/topics.md +116 -0
  39. package/skills/variables.md +146 -0
  40. package/skills/writing.md +153 -0
  41. package/prompts/Branch_Management.md +0 -34
  42. package/prompts/Development_Process.md +0 -89
  43. package/prompts/Jaypie_Agent_Rules.md +0 -110
  44. package/prompts/Jaypie_Auth0_Express_Mongoose.md +0 -736
  45. package/prompts/Jaypie_Browser_and_Frontend_Web_Packages.md +0 -18
  46. package/prompts/Jaypie_CDK_Constructs_and_Patterns.md +0 -430
  47. package/prompts/Jaypie_CICD_with_GitHub_Actions.md +0 -371
  48. package/prompts/Jaypie_Commander_CLI_Package.md +0 -166
  49. package/prompts/Jaypie_Core_Errors_and_Logging.md +0 -39
  50. package/prompts/Jaypie_DynamoDB_Package.md +0 -774
  51. package/prompts/Jaypie_Eslint_NPM_Package.md +0 -78
  52. package/prompts/Jaypie_Express_Package.md +0 -630
  53. package/prompts/Jaypie_Fabric_Commander.md +0 -411
  54. package/prompts/Jaypie_Fabric_LLM.md +0 -312
  55. package/prompts/Jaypie_Fabric_Lambda.md +0 -308
  56. package/prompts/Jaypie_Fabric_MCP.md +0 -316
  57. package/prompts/Jaypie_Fabric_Package.md +0 -513
  58. package/prompts/Jaypie_Fabricator.md +0 -617
  59. package/prompts/Jaypie_Ideal_Project_Structure.md +0 -78
  60. package/prompts/Jaypie_Init_CICD_with_GitHub_Actions.md +0 -1186
  61. package/prompts/Jaypie_Init_Express_on_Lambda.md +0 -115
  62. package/prompts/Jaypie_Init_Jaypie_CDK_Package.md +0 -35
  63. package/prompts/Jaypie_Init_Lambda_Package.md +0 -505
  64. package/prompts/Jaypie_Init_Monorepo_Project.md +0 -44
  65. package/prompts/Jaypie_Init_Project_Subpackage.md +0 -65
  66. package/prompts/Jaypie_Legacy_Patterns.md +0 -15
  67. package/prompts/Jaypie_Llm_Calls.md +0 -449
  68. package/prompts/Jaypie_Llm_Tools.md +0 -155
  69. package/prompts/Jaypie_MCP_Package.md +0 -281
  70. package/prompts/Jaypie_Mocks_and_Testkit.md +0 -137
  71. package/prompts/Jaypie_Repokit.md +0 -103
  72. package/prompts/Jaypie_Scrub.md +0 -177
  73. package/prompts/Jaypie_Streaming.md +0 -467
  74. package/prompts/Templates_CDK_Subpackage.md +0 -115
  75. package/prompts/Templates_Express_Subpackage.md +0 -187
  76. package/prompts/Templates_Project_Monorepo.md +0 -326
  77. package/prompts/Templates_Project_Subpackage.md +0 -93
  78. package/prompts/Write_Efficient_Prompt_Guides.md +0 -48
  79. package/prompts/Write_and_Maintain_Engaging_Readme.md +0 -67
@@ -1,774 +0,0 @@
1
- ---
2
- description: Complete guide to @jaypie/dynamodb single-table design utilities including GSI patterns, key builders, entity operations, and query functions
3
- globs: packages/dynamodb/**
4
- ---
5
-
6
- # Jaypie DynamoDB Package
7
-
8
- Jaypie provides DynamoDB single-table design utilities through `@jaypie/dynamodb`. The package implements a five-GSI pattern for hierarchical data with named access patterns (not gsi1, gsi2, etc.).
9
-
10
- ## Installation
11
-
12
- ```bash
13
- npm install @jaypie/dynamodb
14
- ```
15
-
16
- ## Core Concepts
17
-
18
- ### Single-Table Design
19
-
20
- All entities share a single DynamoDB table with:
21
- - **Primary Key**: `model` (partition) + `id` (sort)
22
- - **Five GSIs**: All use `sequence` as sort key for chronological ordering
23
-
24
- ### Scope
25
-
26
- The `scope` field creates hierarchical relationships:
27
- - Root entities: `scope = "@"` (APEX constant)
28
- - Child entities: `scope = "{parent.model}#{parent.id}"`
29
-
30
- ### GSI Pattern
31
-
32
- | GSI Name | Partition Key | Use Case |
33
- |----------|---------------|----------|
34
- | `indexScope` | `{scope}#{model}` | List all entities under a parent |
35
- | `indexAlias` | `{scope}#{model}#{alias}` | Human-friendly slug lookup |
36
- | `indexClass` | `{scope}#{model}#{class}` | Category filtering |
37
- | `indexType` | `{scope}#{model}#{type}` | Type filtering |
38
- | `indexXid` | `{scope}#{model}#{xid}` | External system ID lookup |
39
-
40
- ## Client Initialization
41
-
42
- Initialize once at application startup:
43
-
44
- ```typescript
45
- import { initClient } from "@jaypie/dynamodb";
46
-
47
- initClient({
48
- tableName: process.env.DYNAMODB_TABLE_NAME,
49
- region: process.env.AWS_REGION, // Optional, defaults to us-east-1
50
- endpoint: process.env.DYNAMODB_ENDPOINT, // Optional, for local dev
51
- });
52
- ```
53
-
54
- For local development with DynamoDB Local:
55
-
56
- ```typescript
57
- initClient({
58
- tableName: "local-table",
59
- endpoint: "http://127.0.0.1:8100",
60
- // Credentials auto-detected for localhost endpoints
61
- });
62
- ```
63
-
64
- ## StorableEntity Interface
65
-
66
- All entities must implement `StorableEntity`:
67
-
68
- ```typescript
69
- import type { StorableEntity } from "@jaypie/dynamodb";
70
-
71
- interface MyRecord extends StorableEntity {
72
- // Primary Key (required)
73
- model: string; // e.g., "record"
74
- id: string; // UUID
75
-
76
- // Required fields
77
- name: string;
78
- scope: string; // APEX or hierarchical
79
- sequence: number; // Date.now()
80
-
81
- // Timestamps (ISO 8601)
82
- createdAt: string;
83
- updatedAt: string;
84
- archivedAt?: string; // Set by archiveEntity
85
- deletedAt?: string; // Set by deleteEntity
86
-
87
- // Optional - trigger GSI population
88
- alias?: string; // Human-friendly slug
89
- class?: string; // Category
90
- type?: string; // Type classification
91
- xid?: string; // External ID
92
- }
93
- ```
94
-
95
- ## Entity Operations
96
-
97
- ### Creating Entities
98
-
99
- Use `putEntity` to create or replace entities. GSI keys are auto-populated:
100
-
101
- ```typescript
102
- import { APEX, putEntity } from "@jaypie/dynamodb";
103
-
104
- const now = new Date().toISOString();
105
-
106
- const record = await putEntity({
107
- entity: {
108
- model: "record",
109
- id: crypto.randomUUID(),
110
- name: "Daily Log",
111
- scope: APEX,
112
- sequence: Date.now(),
113
- alias: "2026-01-07", // Optional
114
- class: "memory", // Optional
115
- createdAt: now,
116
- updatedAt: now,
117
- },
118
- });
119
-
120
- // Result includes auto-populated indexes:
121
- // indexScope: "@#record"
122
- // indexAlias: "@#record#2026-01-07"
123
- // indexClass: "@#record#memory"
124
- ```
125
-
126
- ### Getting Entities
127
-
128
- ```typescript
129
- import { getEntity } from "@jaypie/dynamodb";
130
-
131
- const record = await getEntity({ id: "123", model: "record" });
132
- // Returns entity or null
133
- ```
134
-
135
- ### Updating Entities
136
-
137
- Use `updateEntity` to update. Automatically sets `updatedAt` and re-indexes:
138
-
139
- ```typescript
140
- import { updateEntity } from "@jaypie/dynamodb";
141
-
142
- const updated = await updateEntity({
143
- entity: {
144
- ...existingRecord,
145
- name: "Updated Name",
146
- alias: "new-alias",
147
- },
148
- });
149
- // updatedAt is set automatically
150
- // indexAlias is re-calculated
151
- ```
152
-
153
- ### Soft Delete
154
-
155
- Use `deleteEntity` for soft delete (sets `deletedAt`):
156
-
157
- ```typescript
158
- import { deleteEntity } from "@jaypie/dynamodb";
159
-
160
- await deleteEntity({ id: "123", model: "record" });
161
- // Sets deletedAt and updatedAt timestamps
162
- // Entity excluded from queries by default
163
- ```
164
-
165
- ### Archive
166
-
167
- Use `archiveEntity` for archiving (sets `archivedAt`):
168
-
169
- ```typescript
170
- import { archiveEntity } from "@jaypie/dynamodb";
171
-
172
- await archiveEntity({ id: "123", model: "record" });
173
- // Sets archivedAt and updatedAt timestamps
174
- // Entity excluded from queries by default
175
- ```
176
-
177
- ### Hard Delete
178
-
179
- Use `destroyEntity` to permanently remove:
180
-
181
- ```typescript
182
- import { destroyEntity } from "@jaypie/dynamodb";
183
-
184
- await destroyEntity({ id: "123", model: "record" });
185
- // Permanently removes from table
186
- ```
187
-
188
- ### Hierarchical Entities
189
-
190
- Use `calculateScope` to derive scope from parent:
191
-
192
- ```typescript
193
- import { calculateScope, putEntity, queryByScope } from "@jaypie/dynamodb";
194
-
195
- // Parent reference
196
- const chat = { model: "chat", id: "abc-123" };
197
-
198
- // Calculate child scope
199
- const messageScope = calculateScope(chat); // "chat#abc-123"
200
-
201
- // Create child entity
202
- const message = await putEntity({
203
- entity: {
204
- model: "message",
205
- id: crypto.randomUUID(),
206
- name: "First message",
207
- scope: messageScope,
208
- sequence: Date.now(),
209
- createdAt: now,
210
- updatedAt: now,
211
- },
212
- });
213
- // indexScope: "chat#abc-123#message"
214
-
215
- // Query all messages in chat
216
- const { items } = await queryByScope({ model: "message", scope: messageScope });
217
- ```
218
-
219
- ## Query Functions
220
-
221
- All queries use object parameters and filter soft-deleted and archived records by default.
222
-
223
- ### queryByScope - List by Parent
224
-
225
- List all entities of a model under a parent:
226
-
227
- ```typescript
228
- import { APEX, queryByScope } from "@jaypie/dynamodb";
229
-
230
- // Root-level records
231
- const { items, lastEvaluatedKey } = await queryByScope({
232
- model: "record",
233
- scope: APEX,
234
- });
235
-
236
- // Messages under a chat
237
- const { items: messages } = await queryByScope({
238
- model: "message",
239
- scope: "chat#abc-123",
240
- });
241
- ```
242
-
243
- ### queryByAlias - Human-Friendly Lookup
244
-
245
- Single entity lookup by slug:
246
-
247
- ```typescript
248
- import { APEX, queryByAlias } from "@jaypie/dynamodb";
249
-
250
- const record = await queryByAlias({
251
- alias: "2026-01-07",
252
- model: "record",
253
- scope: APEX,
254
- });
255
- // Returns entity or null
256
- ```
257
-
258
- ### queryByClass / queryByType - Category Filtering
259
-
260
- ```typescript
261
- import { APEX, queryByClass, queryByType } from "@jaypie/dynamodb";
262
-
263
- // All memory records
264
- const { items } = await queryByClass({
265
- model: "record",
266
- scope: APEX,
267
- recordClass: "memory",
268
- });
269
-
270
- // All note-type records
271
- const { items: notes } = await queryByType({
272
- model: "record",
273
- scope: APEX,
274
- type: "note",
275
- });
276
- ```
277
-
278
- ### queryByXid - External ID Lookup
279
-
280
- Single entity lookup by external system ID:
281
-
282
- ```typescript
283
- import { APEX, queryByXid } from "@jaypie/dynamodb";
284
-
285
- const record = await queryByXid({
286
- model: "record",
287
- scope: APEX,
288
- xid: "ext-12345",
289
- });
290
- // Returns entity or null
291
- ```
292
-
293
- ### Query Options
294
-
295
- ```typescript
296
- import type { BaseQueryOptions } from "@jaypie/dynamodb";
297
-
298
- const result = await queryByScope({
299
- model: "record",
300
- scope: APEX,
301
- // BaseQueryOptions:
302
- limit: 25, // Max items to return
303
- ascending: true, // Oldest first (default: false = newest first)
304
- includeDeleted: true, // Include soft-deleted records
305
- includeArchived: true, // Include archived records
306
- startKey: lastEvaluatedKey, // Pagination cursor
307
- });
308
- ```
309
-
310
- ### Pagination
311
-
312
- ```typescript
313
- import { APEX, queryByScope } from "@jaypie/dynamodb";
314
-
315
- let startKey: Record<string, unknown> | undefined;
316
- const allItems: StorableEntity[] = [];
317
-
318
- do {
319
- const { items, lastEvaluatedKey } = await queryByScope({
320
- model: "record",
321
- scope: APEX,
322
- limit: 100,
323
- startKey,
324
- });
325
- allItems.push(...items);
326
- startKey = lastEvaluatedKey;
327
- } while (startKey);
328
- ```
329
-
330
- ## Key Builder Functions
331
-
332
- Use `indexEntity` to auto-populate GSI keys on an entity:
333
-
334
- ```typescript
335
- import { indexEntity } from "@jaypie/dynamodb";
336
-
337
- const indexed = indexEntity({
338
- model: "record",
339
- id: "123",
340
- scope: "@",
341
- alias: "my-alias",
342
- // ...
343
- });
344
- // indexScope: "@#record"
345
- // indexAlias: "@#record#my-alias"
346
- ```
347
-
348
- Use individual key builders for manual key construction:
349
-
350
- ```typescript
351
- import {
352
- buildIndexScope,
353
- buildIndexAlias,
354
- buildIndexClass,
355
- buildIndexType,
356
- buildIndexXid,
357
- } from "@jaypie/dynamodb";
358
-
359
- buildIndexScope("@", "record"); // "@#record"
360
- buildIndexAlias("@", "record", "my-alias"); // "@#record#my-alias"
361
- buildIndexClass("@", "record", "memory"); // "@#record#memory"
362
- buildIndexType("@", "record", "note"); // "@#record#note"
363
- buildIndexXid("@", "record", "ext-123"); // "@#record#ext-123"
364
- ```
365
-
366
- ## Constants
367
-
368
- ```typescript
369
- import {
370
- APEX, // "@" - Root-level marker
371
- SEPARATOR, // "#" - Composite key separator
372
- INDEX_SCOPE, // "indexScope"
373
- INDEX_ALIAS, // "indexAlias"
374
- INDEX_CLASS, // "indexClass"
375
- INDEX_TYPE, // "indexType"
376
- INDEX_XID, // "indexXid"
377
- } from "@jaypie/dynamodb";
378
- ```
379
-
380
- ## Table Schema (CloudFormation/CDK Reference)
381
-
382
- ```yaml
383
- AttributeDefinitions:
384
- - AttributeName: model
385
- AttributeType: S
386
- - AttributeName: id
387
- AttributeType: S
388
- - AttributeName: indexScope
389
- AttributeType: S
390
- - AttributeName: indexAlias
391
- AttributeType: S
392
- - AttributeName: indexClass
393
- AttributeType: S
394
- - AttributeName: indexType
395
- AttributeType: S
396
- - AttributeName: indexXid
397
- AttributeType: S
398
- - AttributeName: sequence
399
- AttributeType: N
400
-
401
- KeySchema:
402
- - AttributeName: model
403
- KeyType: HASH
404
- - AttributeName: id
405
- KeyType: RANGE
406
-
407
- GlobalSecondaryIndexes:
408
- - IndexName: indexScope
409
- KeySchema:
410
- - AttributeName: indexScope
411
- KeyType: HASH
412
- - AttributeName: sequence
413
- KeyType: RANGE
414
- Projection:
415
- ProjectionType: ALL
416
- # Repeat for indexAlias, indexClass, indexType, indexXid
417
- ```
418
-
419
- ## Error Handling
420
-
421
- Functions throw `ConfigurationError` if client is not initialized:
422
-
423
- ```typescript
424
- import { getDocClient } from "@jaypie/dynamodb";
425
-
426
- try {
427
- const client = getDocClient();
428
- } catch (error) {
429
- // ConfigurationError: DynamoDB client not initialized. Call initClient() first.
430
- }
431
- ```
432
-
433
- ## Seed and Export Utilities
434
-
435
- Idempotent seeding and data export for migrations and bootstrapping.
436
-
437
- ### seedEntityIfNotExists
438
-
439
- Seed a single entity if it doesn't already exist (checked by alias):
440
-
441
- ```typescript
442
- import { APEX, seedEntityIfNotExists } from "@jaypie/dynamodb";
443
-
444
- const created = await seedEntityIfNotExists({
445
- alias: "config-main",
446
- model: "config",
447
- name: "Main Configuration",
448
- scope: APEX,
449
- });
450
- // Returns true if created, false if already exists
451
- ```
452
-
453
- ### seedEntities
454
-
455
- Seed multiple entities with idempotency:
456
-
457
- ```typescript
458
- import { APEX, seedEntities } from "@jaypie/dynamodb";
459
-
460
- const result = await seedEntities([
461
- { alias: "vocab-en", model: "vocabulary", name: "English", scope: APEX },
462
- { alias: "vocab-es", model: "vocabulary", name: "Spanish", scope: APEX },
463
- ]);
464
- // result.created: aliases of created entities
465
- // result.skipped: aliases of entities that already existed
466
- // result.errors: { alias, error } for failed operations
467
-
468
- // Dry run (preview without writing)
469
- const preview = await seedEntities(entities, { dryRun: true });
470
-
471
- // Replace existing entities
472
- await seedEntities(entities, { replace: true });
473
- ```
474
-
475
- Auto-generates `id` (UUID), `createdAt`, `updatedAt`, and `sequence` if missing.
476
-
477
- ### exportEntities
478
-
479
- Export entities by model and scope:
480
-
481
- ```typescript
482
- import { APEX, exportEntities } from "@jaypie/dynamodb";
483
-
484
- const { entities, count } = await exportEntities("vocabulary", APEX);
485
- // entities: StorableEntity[] sorted by sequence ascending
486
- // count: number of entities
487
-
488
- // With limit
489
- const { entities: limited } = await exportEntities("vocabulary", APEX, 100);
490
- ```
491
-
492
- ### exportEntitiesToJson
493
-
494
- Export as JSON string:
495
-
496
- ```typescript
497
- import { APEX, exportEntitiesToJson } from "@jaypie/dynamodb";
498
-
499
- const json = await exportEntitiesToJson("vocabulary", APEX);
500
- // Pretty printed by default
501
-
502
- const compact = await exportEntitiesToJson("vocabulary", APEX, false);
503
- // Compact JSON
504
- ```
505
-
506
- ### SeedResult Interface
507
-
508
- ```typescript
509
- interface SeedResult {
510
- created: string[]; // Aliases of created entities
511
- skipped: string[]; // Aliases of skipped entities (already exist)
512
- errors: Array<{ alias: string; error: string }>;
513
- }
514
-
515
- interface SeedOptions {
516
- replace?: boolean; // Overwrite existing (default: false)
517
- dryRun?: boolean; // Preview without writing (default: false)
518
- }
519
-
520
- interface ExportResult<T extends StorableEntity = StorableEntity> {
521
- entities: T[]; // Exported entities
522
- count: number; // Number of entities
523
- }
524
- ```
525
-
526
- ## Testing
527
-
528
- Mock implementations in `@jaypie/testkit`:
529
-
530
- ```typescript
531
- import { vi } from "vitest";
532
-
533
- vi.mock("@jaypie/dynamodb", async () => {
534
- const testkit = await import("@jaypie/testkit/mock");
535
- return testkit;
536
- });
537
-
538
- // Key builders and indexEntity work correctly (delegate to real implementations)
539
- // Query functions return empty results by default
540
- // Entity operations return sensible defaults
541
- // Seed functions return { created: [], skipped: [], errors: [] } by default
542
- // Export functions return { entities: [], count: 0 } by default
543
-
544
- // Customize mock behavior:
545
- import {
546
- exportEntities,
547
- getEntity,
548
- putEntity,
549
- queryByScope,
550
- seedEntities,
551
- } from "@jaypie/testkit/mock";
552
-
553
- queryByScope.mockResolvedValue({
554
- items: [{ id: "123", name: "Test" }],
555
- lastEvaluatedKey: undefined,
556
- });
557
-
558
- getEntity.mockResolvedValue({ id: "123", model: "record", name: "Test" });
559
-
560
- seedEntities.mockResolvedValue({
561
- created: ["entity-1", "entity-2"],
562
- skipped: [],
563
- errors: [],
564
- });
565
-
566
- exportEntities.mockResolvedValue({
567
- entities: [{ id: "123", model: "record" }],
568
- count: 1,
569
- });
570
- ```
571
-
572
- ## Best Practices
573
-
574
- ### Use putEntity, Not Direct Writes
575
-
576
- Always use `putEntity` or `updateEntity` to ensure GSI keys are auto-populated:
577
-
578
- ```typescript
579
- // CORRECT - uses putEntity which calls indexEntity internally
580
- const entity = await putEntity({
581
- entity: {
582
- model: "record",
583
- alias: "my-alias",
584
- // ...
585
- },
586
- });
587
-
588
- // WRONG - bypasses index population
589
- const entity = {
590
- model: "record",
591
- alias: "my-alias",
592
- indexAlias: "@#record#my-alias", // Don't manually set index keys
593
- };
594
- ```
595
-
596
- ### Use indexEntity for Raw Entities
597
-
598
- If you need to prepare an entity before a batch write:
599
-
600
- ```typescript
601
- import { indexEntity } from "@jaypie/dynamodb";
602
-
603
- // Use indexEntity to prepare entities for batch operations
604
- const indexed = indexEntity(myEntity);
605
- ```
606
-
607
- ### Use Meaningful Model Names
608
-
609
- Model names are part of every key. Use short, descriptive names:
610
-
611
- ```typescript
612
- // GOOD
613
- { model: "record" }
614
- { model: "message" }
615
- { model: "chat" }
616
-
617
- // AVOID
618
- { model: "DailyLogRecord" }
619
- { model: "ChatMessage_v2" }
620
- ```
621
-
622
- ### Sequence for Ordering
623
-
624
- Always set `sequence: Date.now()` for chronological ordering in GSI queries:
625
-
626
- ```typescript
627
- const entity = await putEntity({
628
- entity: {
629
- // ...
630
- sequence: Date.now(), // Required for proper ordering
631
- },
632
- });
633
- ```
634
-
635
- ### Soft Delete and Archive Patterns
636
-
637
- Use `deleteEntity` for logical deletion and `archiveEntity` for archival:
638
-
639
- ```typescript
640
- // Soft delete - user action, can be recovered
641
- await deleteEntity({ id: "123", model: "record" });
642
-
643
- // Archive - system action, long-term storage
644
- await archiveEntity({ id: "123", model: "record" });
645
-
646
- // Queries exclude both by default
647
- const { items } = await queryByScope({ model: "record", scope: APEX });
648
-
649
- // Include if needed
650
- const { items: all } = await queryByScope({
651
- model: "record",
652
- scope: APEX,
653
- includeDeleted: true,
654
- includeArchived: true,
655
- });
656
-
657
- // Permanent deletion (use sparingly)
658
- await destroyEntity({ id: "123", model: "record" });
659
- ```
660
-
661
- ## MCP Integration
662
-
663
- The package provides MCP (Model Context Protocol) tools via `@jaypie/dynamodb/mcp` subpath export.
664
-
665
- ### Installation
666
-
667
- ```bash
668
- npm install @jaypie/dynamodb @modelcontextprotocol/sdk
669
- ```
670
-
671
- ### Environment Variables
672
-
673
- | Variable | Required | Default | Description |
674
- |----------|----------|---------|-------------|
675
- | `DYNAMODB_TABLE_NAME` | Yes | - | Table name for operations |
676
- | `DYNAMODB_ENDPOINT` | No | - | Local endpoint (e.g., `http://127.0.0.1:8000`) |
677
- | `AWS_REGION` | No | `us-east-1` | AWS region |
678
- | `PROJECT_NAME` | No | `jaypie` | Container name prefix for docker-compose |
679
-
680
- ### Register MCP Tools
681
-
682
- ```typescript
683
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
684
- import { registerDynamoDbTools } from "@jaypie/dynamodb/mcp";
685
-
686
- const server = new McpServer({ name: "my-server", version: "1.0.0" });
687
-
688
- const { tools } = registerDynamoDbTools({ server });
689
- // tools: ["dynamodb_get", "dynamodb_put", "dynamodb_update", ...]
690
- ```
691
-
692
- ### Available MCP Tools
693
-
694
- #### Entity Operations
695
- | Tool | Description |
696
- |------|-------------|
697
- | `dynamodb_get` | Get entity by id and model |
698
- | `dynamodb_put` | Create or replace an entity |
699
- | `dynamodb_update` | Update entity fields |
700
- | `dynamodb_delete` | Soft delete (sets deletedAt) |
701
- | `dynamodb_archive` | Archive entity (sets archivedAt) |
702
- | `dynamodb_destroy` | Hard delete (permanent) |
703
-
704
- #### Query Operations
705
- | Tool | Description |
706
- |------|-------------|
707
- | `dynamodb_query_scope` | Query by scope |
708
- | `dynamodb_query_alias` | Query by human-friendly alias |
709
- | `dynamodb_query_class` | Query by category classification |
710
- | `dynamodb_query_type` | Query by type classification |
711
- | `dynamodb_query_xid` | Query by external ID |
712
-
713
- #### Admin Operations (Enabled by Default)
714
- | Tool | Description |
715
- |------|-------------|
716
- | `dynamodb_status` | Check DynamoDB connection status |
717
- | `dynamodb_create_table` | Create table with Jaypie GSI schema |
718
- | `dynamodb_generate_docker_compose` | Generate docker-compose.yml for local dev |
719
-
720
- ### Disable Admin Tools
721
-
722
- ```typescript
723
- const { tools } = registerDynamoDbTools({
724
- server,
725
- includeAdmin: false, // Exclude admin tools
726
- });
727
- ```
728
-
729
- ### Auto-Initialization
730
-
731
- MCP tools auto-initialize the DynamoDB client from environment variables. Manual `initClient()` is not required when using MCP tools.
732
-
733
- ### Local Development with MCP
734
-
735
- Generate docker-compose and create table:
736
-
737
- ```typescript
738
- // Use dynamodb_generate_docker_compose tool to get:
739
- // - docker-compose.yml content
740
- // - Environment variables (.env format)
741
-
742
- // Start local DynamoDB
743
- // docker compose up -d
744
-
745
- // Use dynamodb_create_table tool to create table with full GSI schema
746
- ```
747
-
748
- ### Example MCP Tool Usage
749
-
750
- ```json
751
- // dynamodb_put
752
- {
753
- "id": "abc-123",
754
- "model": "record",
755
- "name": "My Record",
756
- "scope": "@",
757
- "alias": "my-record",
758
- "class": "memory"
759
- }
760
-
761
- // dynamodb_query_scope
762
- {
763
- "model": "record",
764
- "scope": "@",
765
- "limit": 10
766
- }
767
-
768
- // dynamodb_update
769
- {
770
- "id": "abc-123",
771
- "model": "record",
772
- "name": "Updated Name"
773
- }
774
- ```