@jaypie/mcp 0.3.1 → 0.3.4

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 (42) hide show
  1. package/dist/aws-B3dW_-bD.js +1202 -0
  2. package/dist/aws-B3dW_-bD.js.map +1 -0
  3. package/dist/index.js +357 -1200
  4. package/dist/index.js.map +1 -1
  5. package/dist/suite.d.ts +1 -0
  6. package/dist/suite.js +1252 -0
  7. package/dist/suite.js.map +1 -0
  8. package/package.json +11 -2
  9. package/prompts/Jaypie_Fabric_MCP.md +22 -2
  10. package/prompts/Jaypie_Fabric_Package.md +86 -0
  11. package/prompts/Jaypie_MCP_Package.md +34 -2
  12. package/release-notes/constructs/1.2.17.md +11 -0
  13. package/release-notes/fabric/0.1.1.md +17 -0
  14. package/release-notes/fabric/0.1.2.md +11 -0
  15. package/release-notes/mcp/0.3.2.md +14 -0
  16. package/release-notes/mcp/0.3.3.md +12 -0
  17. package/release-notes/mcp/0.3.4.md +36 -0
  18. package/skills/agents.md +25 -0
  19. package/skills/aws.md +107 -0
  20. package/skills/cdk.md +141 -0
  21. package/skills/cicd.md +152 -0
  22. package/skills/datadog.md +129 -0
  23. package/skills/debugging.md +148 -0
  24. package/skills/dns.md +134 -0
  25. package/skills/dynamodb.md +140 -0
  26. package/skills/errors.md +142 -0
  27. package/skills/fabric.md +164 -0
  28. package/skills/index.md +7 -0
  29. package/skills/jaypie.md +100 -0
  30. package/skills/legacy.md +97 -0
  31. package/skills/logs.md +160 -0
  32. package/skills/mocks.md +174 -0
  33. package/skills/models.md +195 -0
  34. package/skills/releasenotes.md +94 -0
  35. package/skills/secrets.md +155 -0
  36. package/skills/services.md +175 -0
  37. package/skills/style.md +190 -0
  38. package/skills/tests.md +209 -0
  39. package/skills/tools.md +127 -0
  40. package/skills/topics.md +116 -0
  41. package/skills/variables.md +146 -0
  42. package/skills/writing.md +153 -0
package/skills/dns.md ADDED
@@ -0,0 +1,134 @@
1
+ ---
2
+ description: DNS and domain configuration
3
+ related: cdk, aws
4
+ ---
5
+
6
+ # DNS Configuration
7
+
8
+ Managing domains and DNS for Jaypie applications.
9
+
10
+ ## Route 53 Setup
11
+
12
+ ### Hosted Zone
13
+
14
+ Create a hosted zone for your domain:
15
+
16
+ ```typescript
17
+ import { HostedZone } from "aws-cdk-lib/aws-route53";
18
+
19
+ const zone = HostedZone.fromLookup(this, "Zone", {
20
+ domainName: "example.com",
21
+ });
22
+ ```
23
+
24
+ ### CloudFront Alias
25
+
26
+ Point domain to CloudFront distribution:
27
+
28
+ ```typescript
29
+ import { ARecord, RecordTarget } from "aws-cdk-lib/aws-route53";
30
+ import { CloudFrontTarget } from "aws-cdk-lib/aws-route53-targets";
31
+
32
+ new ARecord(this, "SiteAlias", {
33
+ zone,
34
+ recordName: "app", // app.example.com
35
+ target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
36
+ });
37
+ ```
38
+
39
+ ### API Gateway Custom Domain
40
+
41
+ ```typescript
42
+ import { DomainName } from "aws-cdk-lib/aws-apigatewayv2";
43
+
44
+ const domainName = new DomainName(this, "ApiDomain", {
45
+ domainName: "api.example.com",
46
+ certificate: certificate,
47
+ });
48
+
49
+ new ARecord(this, "ApiAlias", {
50
+ zone,
51
+ recordName: "api",
52
+ target: RecordTarget.fromAlias(new ApiGatewayv2DomainProperties(
53
+ domainName.regionalDomainName,
54
+ domainName.regionalHostedZoneId,
55
+ )),
56
+ });
57
+ ```
58
+
59
+ ## Certificate Management
60
+
61
+ ### ACM Certificate
62
+
63
+ ```typescript
64
+ import { Certificate, CertificateValidation } from "aws-cdk-lib/aws-certificatemanager";
65
+
66
+ const certificate = new Certificate(this, "Certificate", {
67
+ domainName: "example.com",
68
+ subjectAlternativeNames: ["*.example.com"],
69
+ validation: CertificateValidation.fromDns(zone),
70
+ });
71
+ ```
72
+
73
+ ### Cross-Region Certificates
74
+
75
+ CloudFront requires certificates in `us-east-1`:
76
+
77
+ ```typescript
78
+ // In us-east-1 stack
79
+ const cfCertificate = new Certificate(this, "CfCertificate", {
80
+ domainName: "app.example.com",
81
+ validation: CertificateValidation.fromDns(zone),
82
+ });
83
+
84
+ // Export ARN for use in other regions
85
+ new CfnOutput(this, "CertificateArn", {
86
+ value: cfCertificate.certificateArn,
87
+ exportName: "CloudFrontCertificateArn",
88
+ });
89
+ ```
90
+
91
+ ## Environment-Based Domains
92
+
93
+ Map environments to subdomains:
94
+
95
+ | Environment | Domain |
96
+ |-------------|--------|
97
+ | production | app.example.com |
98
+ | sandbox | sandbox.example.com |
99
+ | local | localhost:3000 |
100
+
101
+ ```typescript
102
+ const subdomain = process.env.PROJECT_ENV === "production"
103
+ ? "app"
104
+ : process.env.PROJECT_ENV;
105
+
106
+ new ARecord(this, "Alias", {
107
+ zone,
108
+ recordName: subdomain,
109
+ target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
110
+ });
111
+ ```
112
+
113
+ ## Debugging DNS
114
+
115
+ ### Check DNS Resolution
116
+
117
+ ```bash
118
+ # Check A record
119
+ dig app.example.com A
120
+
121
+ # Check CNAME
122
+ dig app.example.com CNAME
123
+
124
+ # Check with specific nameserver
125
+ dig @ns-123.awsdns-45.com app.example.com
126
+ ```
127
+
128
+ ### Verify Certificate
129
+
130
+ ```bash
131
+ # Check certificate
132
+ openssl s_client -connect app.example.com:443 -servername app.example.com
133
+ ```
134
+
@@ -0,0 +1,140 @@
1
+ ---
2
+ description: DynamoDB patterns and queries
3
+ related: aws, cdk, models
4
+ ---
5
+
6
+ # DynamoDB Patterns
7
+
8
+ Best practices for DynamoDB with Jaypie applications.
9
+
10
+ ## MCP DynamoDB Tools
11
+
12
+ ```
13
+ aws_dynamodb_describe_table - Get table schema and indexes
14
+ aws_dynamodb_query - Query by partition key (efficient)
15
+ aws_dynamodb_scan - Full table scan (use sparingly)
16
+ aws_dynamodb_get_item - Get single item by key
17
+ ```
18
+
19
+ ## Key Design
20
+
21
+ ### Single Table Design
22
+
23
+ Use prefixed keys for multiple entity types:
24
+
25
+ ```typescript
26
+ // User entity
27
+ {
28
+ pk: "USER#123",
29
+ sk: "PROFILE",
30
+ name: "John Doe",
31
+ email: "john@example.com"
32
+ }
33
+
34
+ // User's orders
35
+ {
36
+ pk: "USER#123",
37
+ sk: "ORDER#2024-01-15#abc",
38
+ total: 99.99,
39
+ status: "completed"
40
+ }
41
+ ```
42
+
43
+ ### Access Patterns
44
+
45
+ | Access Pattern | Key Condition |
46
+ |---------------|---------------|
47
+ | Get user profile | pk = USER#123, sk = PROFILE |
48
+ | List user orders | pk = USER#123, sk begins_with ORDER# |
49
+ | Get specific order | pk = USER#123, sk = ORDER#2024-01-15#abc |
50
+
51
+ ## Query Examples
52
+
53
+ ### Query via MCP
54
+
55
+ ```
56
+ # Get user profile
57
+ aws_dynamodb_get_item --tableName "MyTable" --key '{"pk":{"S":"USER#123"},"sk":{"S":"PROFILE"}}'
58
+
59
+ # List user orders
60
+ aws_dynamodb_query --tableName "MyTable" \
61
+ --keyConditionExpression "pk = :pk AND begins_with(sk, :prefix)" \
62
+ --expressionAttributeValues '{":pk":{"S":"USER#123"},":prefix":{"S":"ORDER#"}}'
63
+ ```
64
+
65
+ ### Query in Code
66
+
67
+ ```typescript
68
+ import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
69
+ import { QueryCommand } from "@aws-sdk/lib-dynamodb";
70
+
71
+ const client = new DynamoDBClient({});
72
+
73
+ const result = await client.send(new QueryCommand({
74
+ TableName: process.env.CDK_ENV_TABLE,
75
+ KeyConditionExpression: "pk = :pk AND begins_with(sk, :prefix)",
76
+ ExpressionAttributeValues: {
77
+ ":pk": "USER#123",
78
+ ":prefix": "ORDER#",
79
+ },
80
+ ScanIndexForward: false, // Newest first
81
+ Limit: 10,
82
+ }));
83
+ ```
84
+
85
+ ## GSI Patterns
86
+
87
+ ### By-Status Index
88
+
89
+ ```typescript
90
+ // GSI for querying by status across all users
91
+ {
92
+ pk: "USER#123",
93
+ sk: "ORDER#2024-01-15#abc",
94
+ gsi1pk: "ORDER#pending",
95
+ gsi1sk: "2024-01-15T10:00:00Z",
96
+ }
97
+ ```
98
+
99
+ Query pending orders:
100
+
101
+ ```
102
+ aws_dynamodb_query --tableName "MyTable" --indexName "gsi1" \
103
+ --keyConditionExpression "gsi1pk = :status" \
104
+ --expressionAttributeValues '{":status":{"S":"ORDER#pending"}}'
105
+ ```
106
+
107
+ ## CDK Table Definition
108
+
109
+ ```typescript
110
+ import { JaypieTable } from "@jaypie/constructs";
111
+
112
+ const table = new JaypieTable(this, "DataTable", {
113
+ partitionKey: { name: "pk", type: AttributeType.STRING },
114
+ sortKey: { name: "sk", type: AttributeType.STRING },
115
+ globalSecondaryIndexes: [
116
+ {
117
+ indexName: "gsi1",
118
+ partitionKey: { name: "gsi1pk", type: AttributeType.STRING },
119
+ sortKey: { name: "gsi1sk", type: AttributeType.STRING },
120
+ },
121
+ ],
122
+ });
123
+ ```
124
+
125
+ ## Local Development
126
+
127
+ ```bash
128
+ # Start local DynamoDB
129
+ docker run -p 8000:8000 amazon/dynamodb-local
130
+
131
+ # Create table
132
+ AWS_ACCESS_KEY_ID=local AWS_SECRET_ACCESS_KEY=local \
133
+ aws dynamodb create-table \
134
+ --table-name MyTable \
135
+ --attribute-definitions AttributeName=pk,AttributeType=S AttributeName=sk,AttributeType=S \
136
+ --key-schema AttributeName=pk,KeyType=HASH AttributeName=sk,KeyType=RANGE \
137
+ --billing-mode PAY_PER_REQUEST \
138
+ --endpoint-url http://127.0.0.1:8000
139
+ ```
140
+
@@ -0,0 +1,142 @@
1
+ ---
2
+ description: Error handling with @jaypie/errors
3
+ related: debugging, logs, tests
4
+ ---
5
+
6
+ # Error Handling
7
+
8
+ Jaypie provides structured error types for consistent error handling.
9
+
10
+ ## Core Principle
11
+
12
+ **Never throw vanilla `Error`**. Use Jaypie error types:
13
+
14
+ ```typescript
15
+ import { ConfigurationError, NotFoundError } from "jaypie";
16
+
17
+ // BAD
18
+ throw new Error("Missing API key");
19
+
20
+ // GOOD
21
+ throw new ConfigurationError("Missing API key");
22
+ ```
23
+
24
+ ## Error Types
25
+
26
+ | Error | HTTP Status | Use When |
27
+ |-------|-------------|----------|
28
+ | BadRequestError | 400 | Invalid input from client |
29
+ | UnauthorizedError | 401 | Authentication required |
30
+ | ForbiddenError | 403 | Authenticated but not permitted |
31
+ | NotFoundError | 404 | Resource doesn't exist |
32
+ | ConfigurationError | 500 | Missing or invalid config |
33
+ | InternalError | 500 | Unexpected server error |
34
+
35
+ ## Usage Examples
36
+
37
+ ### Bad Request
38
+
39
+ ```typescript
40
+ import { BadRequestError } from "jaypie";
41
+
42
+ if (!request.body.email) {
43
+ throw new BadRequestError("Email is required");
44
+ }
45
+
46
+ if (!isValidEmail(request.body.email)) {
47
+ throw new BadRequestError("Invalid email format");
48
+ }
49
+ ```
50
+
51
+ ### Not Found
52
+
53
+ ```typescript
54
+ import { NotFoundError } from "jaypie";
55
+
56
+ const user = await User.findById(userId);
57
+ if (!user) {
58
+ throw new NotFoundError(`User ${userId} not found`);
59
+ }
60
+ ```
61
+
62
+ ### Configuration Error
63
+
64
+ ```typescript
65
+ import { ConfigurationError } from "jaypie";
66
+
67
+ if (!process.env.API_KEY) {
68
+ throw new ConfigurationError("API_KEY environment variable is required");
69
+ }
70
+ ```
71
+
72
+ ### Unauthorized vs Forbidden
73
+
74
+ ```typescript
75
+ import { UnauthorizedError, ForbiddenError } from "jaypie";
76
+
77
+ // No credentials provided
78
+ if (!token) {
79
+ throw new UnauthorizedError("Authentication required");
80
+ }
81
+
82
+ // Credentials provided but insufficient permission
83
+ if (!user.hasRole("admin")) {
84
+ throw new ForbiddenError("Admin access required");
85
+ }
86
+ ```
87
+
88
+ ## Error Context
89
+
90
+ Add context to errors for debugging:
91
+
92
+ ```typescript
93
+ import { NotFoundError } from "jaypie";
94
+
95
+ throw new NotFoundError("User not found", {
96
+ context: {
97
+ userId,
98
+ requestId: req.id,
99
+ searchedTables: ["users", "legacy_users"],
100
+ },
101
+ });
102
+ ```
103
+
104
+ ## Error Handling in Handlers
105
+
106
+ Jaypie handlers automatically catch and format errors:
107
+
108
+ ```typescript
109
+ import { lambdaHandler } from "@jaypie/lambda";
110
+ import { NotFoundError } from "jaypie";
111
+
112
+ export const handler = lambdaHandler(async (event) => {
113
+ const item = await getItem(event.id);
114
+ if (!item) {
115
+ throw new NotFoundError("Item not found");
116
+ // Returns: { statusCode: 404, body: { error: "Item not found" } }
117
+ }
118
+ return item;
119
+ });
120
+ ```
121
+
122
+ ## Testing Errors
123
+
124
+ ```typescript
125
+ import { expect, it } from "vitest";
126
+ import { NotFoundError } from "jaypie";
127
+
128
+ it("throws NotFoundError when user missing", async () => {
129
+ await expect(getUser("invalid-id"))
130
+ .rejects
131
+ .toThrow(NotFoundError);
132
+ });
133
+
134
+ it("includes context in error", async () => {
135
+ try {
136
+ await getUser("invalid-id");
137
+ } catch (error) {
138
+ expect(error.context.userId).toBe("invalid-id");
139
+ }
140
+ });
141
+ ```
142
+
@@ -0,0 +1,164 @@
1
+ ---
2
+ description: Fabric service patterns and adapters
3
+ related: services, errors, tools
4
+ ---
5
+
6
+ # Fabric Services
7
+
8
+ Fabric provides a unified service pattern that works across CLI, Lambda, LLM tools, and MCP.
9
+
10
+ ## Core Concept
11
+
12
+ Define a service once, deploy it anywhere:
13
+
14
+ ```typescript
15
+ import { fabricService } from "@jaypie/fabric";
16
+
17
+ const greetService = fabricService({
18
+ alias: "greet",
19
+ description: "Greet a user by name",
20
+ input: {
21
+ name: {
22
+ type: String,
23
+ required: true,
24
+ description: "Name to greet",
25
+ },
26
+ },
27
+ service: async ({ name }) => {
28
+ return `Hello, ${name}!`;
29
+ },
30
+ });
31
+ ```
32
+
33
+ ## Adapters
34
+
35
+ ### Lambda Handler
36
+
37
+ ```typescript
38
+ import { fabricLambdaHandler } from "@jaypie/fabric";
39
+
40
+ export const handler = fabricLambdaHandler(greetService);
41
+ // Invoked via Lambda with { name: "World" }
42
+ ```
43
+
44
+ ### CLI Command
45
+
46
+ ```typescript
47
+ import { fabricCommand } from "@jaypie/fabric";
48
+
49
+ const program = new Command();
50
+ program.addCommand(fabricCommand(greetService));
51
+ // $ cli greet --name World
52
+ ```
53
+
54
+ ### MCP Tool
55
+
56
+ ```typescript
57
+ import { fabricMcpTool } from "@jaypie/fabric";
58
+
59
+ server.tool(...fabricMcpTool(greetService));
60
+ // Available as MCP tool "greet"
61
+ ```
62
+
63
+ ### LLM Tool
64
+
65
+ ```typescript
66
+ import { fabricLlmTool } from "@jaypie/fabric";
67
+
68
+ const tools = [fabricLlmTool(greetService)];
69
+ // Available to LLM as function call
70
+ ```
71
+
72
+ ## Service Suites
73
+
74
+ Group related services:
75
+
76
+ ```typescript
77
+ import { createServiceSuite, fabricService } from "@jaypie/fabric";
78
+
79
+ const userService = fabricService({
80
+ alias: "user_get",
81
+ description: "Get user by ID",
82
+ input: { id: { type: String, required: true } },
83
+ service: async ({ id }) => User.findById(id),
84
+ });
85
+
86
+ const userListService = fabricService({
87
+ alias: "user_list",
88
+ description: "List all users",
89
+ input: {},
90
+ service: async () => User.find(),
91
+ });
92
+
93
+ const suite = createServiceSuite({
94
+ name: "users",
95
+ version: "1.0.0",
96
+ });
97
+
98
+ suite.register(userService, "users");
99
+ suite.register(userListService, "users");
100
+ ```
101
+
102
+ ## Input Validation
103
+
104
+ Fabric validates inputs automatically:
105
+
106
+ ```typescript
107
+ const service = fabricService({
108
+ input: {
109
+ email: {
110
+ type: String,
111
+ required: true,
112
+ description: "User email address",
113
+ },
114
+ count: {
115
+ type: Number,
116
+ required: false,
117
+ description: "Number of results",
118
+ },
119
+ status: {
120
+ type: ["active", "inactive"] as const,
121
+ required: false,
122
+ description: "Filter by status",
123
+ },
124
+ },
125
+ service: async ({ email, count, status }) => {
126
+ // email: string (validated)
127
+ // count: number | undefined
128
+ // status: "active" | "inactive" | undefined
129
+ },
130
+ });
131
+ ```
132
+
133
+ ## Error Handling
134
+
135
+ Fabric services use Jaypie errors:
136
+
137
+ ```typescript
138
+ import { fabricService } from "@jaypie/fabric";
139
+ import { NotFoundError, BadRequestError } from "jaypie";
140
+
141
+ const service = fabricService({
142
+ alias: "user_get",
143
+ input: { id: { type: String, required: true } },
144
+ service: async ({ id }) => {
145
+ if (!isValidId(id)) {
146
+ throw new BadRequestError("Invalid user ID format");
147
+ }
148
+ const user = await User.findById(id);
149
+ if (!user) {
150
+ throw new NotFoundError(`User ${id} not found`);
151
+ }
152
+ return user;
153
+ },
154
+ });
155
+ ```
156
+
157
+ ## Best Practices
158
+
159
+ 1. **Single Responsibility**: Each service does one thing
160
+ 2. **Descriptive Aliases**: Use `noun_verb` format (`user_get`, `order_create`)
161
+ 3. **Clear Descriptions**: Write for AI tools that need context
162
+ 4. **Input Documentation**: Describe what each input expects
163
+ 5. **Return Types**: Return JSON-serializable data
164
+
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: Skill directory listing
3
+ ---
4
+
5
+ # Jaypie Skills
6
+
7
+ Query the Jaypie MCP `skill` tool with one of the following alias keywords `mcp__jaypie__skill(alias: String)`:
@@ -0,0 +1,100 @@
1
+ ---
2
+ description: Jaypie overview and core concepts
3
+ ---
4
+
5
+ # Introduction to Jaypie
6
+
7
+ Jaypie is a complete stack framework for building multi-environment cloud applications on AWS using TypeScript/Node.js.
8
+
9
+ ## Core Packages
10
+
11
+ ### Main Package: `jaypie`
12
+
13
+ The main package provides:
14
+ - **Secrets**: AWS Secrets Manager integration
15
+ - **Errors**: Structured error types (ConfigurationError, etc.)
16
+ - **Events**: Event parsing for Lambda handlers
17
+ - **Lifecycle**: Handler lifecycle management
18
+ - **Logging**: Structured logging with context
19
+ - **Queues**: SQS messaging utilities
20
+
21
+ ```typescript
22
+ import {
23
+ getSecret,
24
+ log,
25
+ ConfigurationError,
26
+ HTTP,
27
+ PROJECT
28
+ } from "jaypie";
29
+ ```
30
+
31
+ ### Infrastructure: `@jaypie/constructs`
32
+
33
+ CDK constructs for AWS infrastructure:
34
+ - Lambda functions with best practices
35
+ - SQS queues with DLQ
36
+ - S3 buckets with encryption
37
+ - CloudFront distributions
38
+ - Secrets Manager secrets
39
+
40
+ ### Testing: `@jaypie/testkit`
41
+
42
+ Testing utilities and mocks:
43
+ - Mock implementations for all Jaypie functions
44
+ - Vitest configuration helpers
45
+ - Test data fabrication
46
+
47
+ ## Project Structure
48
+
49
+ Jaypie projects use npm workspaces:
50
+
51
+ ```
52
+ project/
53
+ ├── packages/ # npm packages
54
+ │ ├── api/ # Express API
55
+ │ └── lib/ # Shared library
56
+ ├── stacks/ # CDK infrastructure
57
+ │ └── cdk/ # CDK app
58
+ └── package.json # Root workspace config
59
+ ```
60
+
61
+ ## Key Conventions
62
+
63
+ ### Environment Variables
64
+
65
+ | Variable | Purpose |
66
+ |----------|---------|
67
+ | `PROJECT_ENV` | Environment: local, sandbox, production |
68
+ | `PROJECT_KEY` | Project identifier for logging |
69
+ | `PROJECT_NONCE` | Unique resource identifier |
70
+ | `LOG_LEVEL` | Log level: trace, debug, info, warn, error |
71
+
72
+ ### Error Handling
73
+
74
+ Never throw vanilla `Error`. Use Jaypie errors:
75
+
76
+ ```typescript
77
+ import { ConfigurationError, NotFoundError } from "jaypie";
78
+
79
+ if (!config.required) {
80
+ throw new ConfigurationError("Missing required config");
81
+ }
82
+ ```
83
+
84
+ ### Logging
85
+
86
+ Use structured logging with context:
87
+
88
+ ```typescript
89
+ import { log } from "jaypie";
90
+
91
+ log.info("Processing request", { userId, action });
92
+ log.error("Request failed", { error: error.message });
93
+ ```
94
+
95
+ ## Next Steps
96
+
97
+ - `skill("style")` - Code style conventions
98
+ - `skill("errors")` - Error handling patterns
99
+ - `skill("tests")` - Testing with Vitest
100
+ - `skill("cdk")` - Infrastructure with CDK