@jaypie/mcp 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/createMcpServer.d.ts +7 -1
- package/dist/index.js +22 -2088
- package/dist/index.js.map +1 -1
- package/dist/suite.js +1197 -7
- package/dist/suite.js.map +1 -1
- package/package.json +1 -2
- package/release-notes/constructs/1.2.18.md +12 -0
- package/release-notes/fabric/0.1.3.md +25 -0
- package/release-notes/fabric/0.1.4.md +42 -0
- package/release-notes/llm/1.2.5.md +25 -0
- package/release-notes/llm/1.2.6.md +55 -0
- package/release-notes/mcp/0.4.0.md +27 -0
- package/release-notes/testkit/1.2.15.md +23 -0
- package/skills/agents.md +18 -8
- package/skills/aws.md +232 -60
- package/skills/datadog.md +98 -64
- package/skills/dynamodb.md +37 -28
- package/skills/fabric.md +30 -3
- package/skills/issues.md +55 -0
- package/skills/llm.md +381 -0
- package/skills/secrets.md +74 -18
- package/skills/skills.md +23 -0
- package/skills/tools-aws.md +148 -0
- package/skills/tools-datadog.md +190 -0
- package/skills/tools-dynamodb.md +140 -0
- package/skills/tools.md +19 -54
- package/skills/vocabulary.md +25 -0
- package/dist/aws-B3dW_-bD.js +0 -1202
- package/dist/aws-B3dW_-bD.js.map +0 -1
- package/prompts/Branch_Management.md +0 -34
- package/prompts/Development_Process.md +0 -89
- package/prompts/Jaypie_Agent_Rules.md +0 -110
- package/prompts/Jaypie_Auth0_Express_Mongoose.md +0 -736
- package/prompts/Jaypie_Browser_and_Frontend_Web_Packages.md +0 -18
- package/prompts/Jaypie_CDK_Constructs_and_Patterns.md +0 -430
- package/prompts/Jaypie_CICD_with_GitHub_Actions.md +0 -371
- package/prompts/Jaypie_Commander_CLI_Package.md +0 -166
- package/prompts/Jaypie_Core_Errors_and_Logging.md +0 -39
- package/prompts/Jaypie_DynamoDB_Package.md +0 -774
- package/prompts/Jaypie_Eslint_NPM_Package.md +0 -78
- package/prompts/Jaypie_Express_Package.md +0 -630
- package/prompts/Jaypie_Fabric_Commander.md +0 -411
- package/prompts/Jaypie_Fabric_LLM.md +0 -312
- package/prompts/Jaypie_Fabric_Lambda.md +0 -308
- package/prompts/Jaypie_Fabric_MCP.md +0 -316
- package/prompts/Jaypie_Fabric_Package.md +0 -599
- package/prompts/Jaypie_Fabricator.md +0 -617
- package/prompts/Jaypie_Ideal_Project_Structure.md +0 -78
- package/prompts/Jaypie_Init_CICD_with_GitHub_Actions.md +0 -1186
- package/prompts/Jaypie_Init_Express_on_Lambda.md +0 -115
- package/prompts/Jaypie_Init_Jaypie_CDK_Package.md +0 -35
- package/prompts/Jaypie_Init_Lambda_Package.md +0 -505
- package/prompts/Jaypie_Init_Monorepo_Project.md +0 -44
- package/prompts/Jaypie_Init_Project_Subpackage.md +0 -65
- package/prompts/Jaypie_Legacy_Patterns.md +0 -15
- package/prompts/Jaypie_Llm_Calls.md +0 -449
- package/prompts/Jaypie_Llm_Tools.md +0 -155
- package/prompts/Jaypie_MCP_Package.md +0 -281
- package/prompts/Jaypie_Mocks_and_Testkit.md +0 -137
- package/prompts/Jaypie_Repokit.md +0 -103
- package/prompts/Jaypie_Scrub.md +0 -177
- package/prompts/Jaypie_Streaming.md +0 -467
- package/prompts/Templates_CDK_Subpackage.md +0 -115
- package/prompts/Templates_Express_Subpackage.md +0 -187
- package/prompts/Templates_Project_Monorepo.md +0 -326
- package/prompts/Templates_Project_Subpackage.md +0 -93
- package/prompts/Write_Efficient_Prompt_Guides.md +0 -48
- package/prompts/Write_and_Maintain_Engaging_Readme.md +0 -67
- package/skills/topics.md +0 -116
- /package/skills/{writing.md → documentation.md} +0 -0
package/skills/llm.md
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Using @jaypie/llm for unified LLM access
|
|
3
|
+
related: fabric, tools, tests
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @jaypie/llm
|
|
7
|
+
|
|
8
|
+
Unified interface for calling LLM providers with multi-turn conversations, tool calling, streaming, and structured output.
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import Llm from "@jaypie/llm";
|
|
14
|
+
|
|
15
|
+
// Auto-detect provider from model name
|
|
16
|
+
const response = await Llm.operate("What is 2+2?", { model: "claude-sonnet-4" });
|
|
17
|
+
console.log(response.content); // "4"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Providers and Models
|
|
21
|
+
|
|
22
|
+
| Provider | Match Keywords | Default Model |
|
|
23
|
+
|----------|----------------|---------------|
|
|
24
|
+
| OpenAI | "openai", "gpt", /^o\d/ | gpt-5.1 |
|
|
25
|
+
| Anthropic | "anthropic", "claude", "haiku", "opus", "sonnet" | claude-sonnet-4-5 |
|
|
26
|
+
| Gemini | "gemini", "google" | gemini-3-pro-preview |
|
|
27
|
+
| OpenRouter | "openrouter" | z-ai/glm-4.7 |
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// Provider auto-detected from model
|
|
31
|
+
await Llm.operate(input, { model: "gpt-5.1" }); // OpenAI
|
|
32
|
+
await Llm.operate(input, { model: "claude-opus-4" }); // Anthropic
|
|
33
|
+
await Llm.operate(input, { model: "gemini-3" }); // Gemini
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Core Methods
|
|
37
|
+
|
|
38
|
+
### operate() - Multi-turn with Tools
|
|
39
|
+
|
|
40
|
+
The primary method for complex interactions:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const response = await Llm.operate(input, {
|
|
44
|
+
model: "gpt-5.1",
|
|
45
|
+
system: "You are a helpful assistant",
|
|
46
|
+
tools: toolkit,
|
|
47
|
+
turns: 5, // Allow up to 5 conversation turns
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Response structure
|
|
51
|
+
response.content; // string | object (structured output)
|
|
52
|
+
response.history; // LlmHistory - for follow-up calls
|
|
53
|
+
response.usage; // Token usage per turn
|
|
54
|
+
response.reasoning; // Extended thinking (if available)
|
|
55
|
+
response.status; // "completed" | "incomplete" | "in_progress"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### send() - Simple Completions
|
|
59
|
+
|
|
60
|
+
For single-shot text completions:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const response = await Llm.send("Explain REST APIs", {
|
|
64
|
+
model: "claude-sonnet-4",
|
|
65
|
+
system: "You are a technical writer",
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### stream() - Streaming Responses
|
|
70
|
+
|
|
71
|
+
For real-time output:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
for await (const chunk of Llm.stream("Tell me a story", { model: "gpt-5.1" })) {
|
|
75
|
+
switch (chunk.type) {
|
|
76
|
+
case "text":
|
|
77
|
+
process.stdout.write(chunk.content);
|
|
78
|
+
break;
|
|
79
|
+
case "tool_call":
|
|
80
|
+
console.log(`Tool: ${chunk.toolCall.name}`);
|
|
81
|
+
break;
|
|
82
|
+
case "done":
|
|
83
|
+
console.log("Usage:", chunk.usage);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Tool Calling
|
|
90
|
+
|
|
91
|
+
### Define Tools with Toolkit
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import Llm, { Toolkit } from "@jaypie/llm";
|
|
95
|
+
|
|
96
|
+
const toolkit = new Toolkit([
|
|
97
|
+
{
|
|
98
|
+
name: "get_weather",
|
|
99
|
+
description: "Get current weather for a city",
|
|
100
|
+
type: "function",
|
|
101
|
+
parameters: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
city: { type: "string", description: "City name" },
|
|
105
|
+
},
|
|
106
|
+
required: ["city"],
|
|
107
|
+
},
|
|
108
|
+
call: async ({ city }) => {
|
|
109
|
+
// Actual implementation
|
|
110
|
+
return { temp: 72, conditions: "sunny" };
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
const response = await Llm.operate("What's the weather in NYC?", {
|
|
116
|
+
model: "gpt-5.1",
|
|
117
|
+
tools: toolkit,
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Built-in Tools
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import Llm, { tools, JaypieToolkit } from "@jaypie/llm";
|
|
125
|
+
|
|
126
|
+
// Use individual tools
|
|
127
|
+
const response = await Llm.operate("Roll 2d6", {
|
|
128
|
+
model: "gpt-5.1",
|
|
129
|
+
tools, // Includes: random, roll, time, weather
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Or use the pre-configured toolkit
|
|
133
|
+
const toolkit = new JaypieToolkit();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Fabric Services as Tools
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { fabricLlmTool } from "@jaypie/fabric";
|
|
140
|
+
|
|
141
|
+
const greetTool = fabricLlmTool(greetService);
|
|
142
|
+
const toolkit = new Toolkit([greetTool]);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Structured Output
|
|
146
|
+
|
|
147
|
+
### Natural Schema
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const result = await Llm.operate("Extract contact info from: John Doe, john@example.com, 555-1234", {
|
|
151
|
+
model: "gpt-5.1",
|
|
152
|
+
format: {
|
|
153
|
+
name: String,
|
|
154
|
+
email: String,
|
|
155
|
+
phone: String,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
// result.content = { name: "John Doe", email: "john@example.com", phone: "555-1234" }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Zod Schema
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { z } from "zod";
|
|
165
|
+
|
|
166
|
+
const PersonSchema = z.object({
|
|
167
|
+
name: z.string(),
|
|
168
|
+
age: z.number(),
|
|
169
|
+
hobbies: z.array(z.string()),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const result = await Llm.operate("Parse: Alice is 30 and likes hiking and reading", {
|
|
173
|
+
model: "gpt-5.1",
|
|
174
|
+
format: PersonSchema,
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Conversation History
|
|
179
|
+
|
|
180
|
+
Continue conversations across calls:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
const first = await Llm.operate("My name is Alice", { model: "gpt-5.1" });
|
|
184
|
+
|
|
185
|
+
const second = await Llm.operate("What's my name?", {
|
|
186
|
+
model: "gpt-5.1",
|
|
187
|
+
history: first.history,
|
|
188
|
+
});
|
|
189
|
+
// second.content = "Your name is Alice"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Input with Files and Images
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
const response = await Llm.operate([
|
|
196
|
+
"Analyze these documents",
|
|
197
|
+
{ file: "report.pdf", bucket: "my-bucket" },
|
|
198
|
+
{ image: "chart.png" },
|
|
199
|
+
], {
|
|
200
|
+
model: "claude-sonnet-4",
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Placeholders and Data
|
|
205
|
+
|
|
206
|
+
Substitute data into prompts:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const response = await Llm.operate("Summarize the article about {{topic}}", {
|
|
210
|
+
model: "gpt-5.1",
|
|
211
|
+
data: { topic: "climate change" },
|
|
212
|
+
placeholders: { input: true },
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Lifecycle Hooks
|
|
217
|
+
|
|
218
|
+
Monitor and react to LLM operations:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
const response = await Llm.operate(input, {
|
|
222
|
+
model: "gpt-5.1",
|
|
223
|
+
hooks: {
|
|
224
|
+
beforeEachModelRequest: ({ providerRequest }) => {
|
|
225
|
+
console.log("Sending request...");
|
|
226
|
+
},
|
|
227
|
+
afterEachModelResponse: ({ content, usage }) => {
|
|
228
|
+
console.log(`Tokens: ${usage.total}`);
|
|
229
|
+
},
|
|
230
|
+
beforeEachTool: ({ toolName, args }) => {
|
|
231
|
+
console.log(`Calling ${toolName} with`, args);
|
|
232
|
+
},
|
|
233
|
+
afterEachTool: ({ result, toolName }) => {
|
|
234
|
+
console.log(`${toolName} returned:`, result);
|
|
235
|
+
},
|
|
236
|
+
onToolError: ({ error, toolName }) => {
|
|
237
|
+
console.error(`${toolName} failed:`, error);
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Fallback Providers
|
|
244
|
+
|
|
245
|
+
Configure a chain of fallback providers that automatically retry failed calls when the primary provider fails:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Instance-level configuration
|
|
249
|
+
const llm = new Llm("anthropic", {
|
|
250
|
+
model: "claude-sonnet-4",
|
|
251
|
+
fallback: [
|
|
252
|
+
{ provider: "openai", model: "gpt-4o" },
|
|
253
|
+
{ provider: "gemini", model: "gemini-2.0-flash" },
|
|
254
|
+
],
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Per-call override
|
|
258
|
+
const response = await llm.operate(input, {
|
|
259
|
+
fallback: [{ provider: "openai", model: "gpt-4o" }],
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Disable fallback for specific call
|
|
263
|
+
const response = await llm.operate(input, { fallback: false });
|
|
264
|
+
|
|
265
|
+
// Static method with fallback
|
|
266
|
+
const response = await Llm.operate(input, {
|
|
267
|
+
model: "claude-sonnet-4",
|
|
268
|
+
fallback: [{ provider: "openai", model: "gpt-4o" }],
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Fallback Response Metadata
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
response.provider; // Which provider handled the request
|
|
276
|
+
response.fallbackUsed; // true if a fallback was used
|
|
277
|
+
response.fallbackAttempts; // Number of providers tried (1 = primary only)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Instance Usage
|
|
281
|
+
|
|
282
|
+
For repeated calls with same configuration:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const llm = new Llm("anthropic", {
|
|
286
|
+
model: "claude-sonnet-4",
|
|
287
|
+
system: "You are a code reviewer",
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const review1 = await llm.operate(code1);
|
|
291
|
+
const review2 = await llm.operate(code2);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Environment Variables
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
OPENAI_API_KEY # Required for OpenAI
|
|
298
|
+
ANTHROPIC_API_KEY # Required for Anthropic
|
|
299
|
+
GOOGLE_API_KEY # Required for Gemini
|
|
300
|
+
OPENROUTER_API_KEY # Required for OpenRouter
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Keys are resolved via `getEnvSecret()` which supports AWS Secrets Manager.
|
|
304
|
+
|
|
305
|
+
## Error Handling
|
|
306
|
+
|
|
307
|
+
The package auto-retries rate limits and transient errors:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
try {
|
|
311
|
+
const response = await Llm.operate(input, { model: "gpt-5.1" });
|
|
312
|
+
if (response.status !== "completed") {
|
|
313
|
+
console.log("Incomplete:", response.error);
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
// Unrecoverable errors (auth, validation) throw
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Testing Pattern
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { describe, expect, it, vi } from "vitest";
|
|
324
|
+
import Llm, { Toolkit } from "@jaypie/llm";
|
|
325
|
+
|
|
326
|
+
describe("LLM Integration", () => {
|
|
327
|
+
it("calls tool and returns response", async () => {
|
|
328
|
+
const mockTool = {
|
|
329
|
+
name: "calculate",
|
|
330
|
+
description: "Perform calculation",
|
|
331
|
+
type: "function",
|
|
332
|
+
parameters: { type: "object", properties: { expr: { type: "string" } } },
|
|
333
|
+
call: vi.fn().mockResolvedValue("42"),
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const toolkit = new Toolkit([mockTool]);
|
|
337
|
+
const response = await Llm.operate("Calculate 6*7", {
|
|
338
|
+
model: "gpt-5.1",
|
|
339
|
+
tools: toolkit,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
expect(mockTool.call).toHaveBeenCalled();
|
|
343
|
+
expect(response.status).toBe("completed");
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Best Practices
|
|
349
|
+
|
|
350
|
+
1. **Use operate() over send()** - More flexible, handles tools and structure
|
|
351
|
+
2. **Set turns appropriately** - Default is 1; increase for tool-heavy workflows
|
|
352
|
+
3. **Provide clear tool descriptions** - LLMs use these to decide which tool to call
|
|
353
|
+
4. **Use structured output** - More reliable than parsing free text
|
|
354
|
+
5. **Track usage** - Monitor `response.usage` for cost management
|
|
355
|
+
6. **Handle incomplete status** - Check `response.status` for tool errors or limits
|
|
356
|
+
7. **Configure fallbacks** - Set up fallback providers for resilience against outages
|
|
357
|
+
|
|
358
|
+
## Common Options
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
interface LlmOperateOptions {
|
|
362
|
+
data?: Record<string, any>; // Placeholder substitution data
|
|
363
|
+
fallback?: LlmFallbackConfig[] | false; // Fallback provider chain
|
|
364
|
+
format?: JsonObject | ZodType; // Structured output schema
|
|
365
|
+
history?: LlmHistory; // Previous conversation
|
|
366
|
+
hooks?: LlmHooks; // Lifecycle callbacks
|
|
367
|
+
instructions?: string; // Additional instructions
|
|
368
|
+
model?: string; // Model override
|
|
369
|
+
system?: string; // System prompt
|
|
370
|
+
tools?: LlmTool[] | Toolkit; // Available tools
|
|
371
|
+
turns?: boolean | number; // Max conversation turns
|
|
372
|
+
user?: string; // User ID for logging
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
interface LlmFallbackConfig {
|
|
376
|
+
provider: string; // Provider name (e.g., "openai", "anthropic", "gemini")
|
|
377
|
+
model?: string; // Model to use (optional, uses provider default)
|
|
378
|
+
apiKey?: string; // API key (optional, uses environment variable)
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
package/skills/secrets.md
CHANGED
|
@@ -5,26 +5,52 @@ related: aws, cdk, variables
|
|
|
5
5
|
|
|
6
6
|
# Secret Management
|
|
7
7
|
|
|
8
|
-
Jaypie uses AWS Secrets Manager for secure credential storage.
|
|
8
|
+
Jaypie uses AWS Secrets Manager for secure credential storage, with environment-aware resolution that works seamlessly in both local development and Lambda.
|
|
9
9
|
|
|
10
10
|
## Basic Usage
|
|
11
11
|
|
|
12
|
+
Use `getEnvSecret` for environment-aware secret resolution:
|
|
13
|
+
|
|
12
14
|
```typescript
|
|
13
|
-
import {
|
|
15
|
+
import { getEnvSecret } from "jaypie";
|
|
14
16
|
|
|
15
|
-
const apiKey = await
|
|
16
|
-
const dbUri = await
|
|
17
|
+
const apiKey = await getEnvSecret("ANTHROPIC_API_KEY");
|
|
18
|
+
const dbUri = await getEnvSecret("MONGODB_URI");
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
### How getEnvSecret Works
|
|
22
|
+
|
|
23
|
+
`getEnvSecret` checks environment variables in order:
|
|
24
|
+
|
|
25
|
+
1. `SECRET_{name}` - If found, fetches from AWS Secrets Manager
|
|
26
|
+
2. `{name}_SECRET` - If found, fetches from AWS Secrets Manager
|
|
27
|
+
3. `{name}` - Returns direct value without AWS call
|
|
28
|
+
|
|
29
|
+
This allows the same code to work locally (with direct env values) and in Lambda (with secret references).
|
|
30
|
+
|
|
31
|
+
## Loading Multiple Secrets
|
|
32
|
+
|
|
33
|
+
Use `loadEnvSecrets` during handler initialization:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { loadEnvSecrets } from "jaypie";
|
|
37
|
+
|
|
38
|
+
// Load secrets and set in process.env
|
|
39
|
+
await loadEnvSecrets("ANTHROPIC_API_KEY", "OPENAI_API_KEY", "MONGODB_URI");
|
|
40
|
+
|
|
41
|
+
// Now available as process.env.ANTHROPIC_API_KEY, etc.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## CDK Configuration
|
|
20
45
|
|
|
21
46
|
Reference secrets via environment variables in CDK:
|
|
22
47
|
|
|
23
48
|
```typescript
|
|
24
49
|
const handler = new JaypieLambda(this, "Handler", {
|
|
25
50
|
environment: {
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
// SECRET_ prefix triggers AWS Secrets Manager fetch
|
|
52
|
+
SECRET_MONGODB_URI: "my-project/mongodb-uri",
|
|
53
|
+
SECRET_API_KEY: "my-project/third-party-api-key",
|
|
28
54
|
},
|
|
29
55
|
});
|
|
30
56
|
```
|
|
@@ -32,10 +58,23 @@ const handler = new JaypieLambda(this, "Handler", {
|
|
|
32
58
|
In code:
|
|
33
59
|
|
|
34
60
|
```typescript
|
|
35
|
-
|
|
36
|
-
const mongoUri = await
|
|
61
|
+
// getEnvSecret sees SECRET_MONGODB_URI and fetches from Secrets Manager
|
|
62
|
+
const mongoUri = await getEnvSecret("MONGODB_URI");
|
|
37
63
|
```
|
|
38
64
|
|
|
65
|
+
## Direct Secret Access
|
|
66
|
+
|
|
67
|
+
Use `getSecret` when you need to fetch by exact AWS secret name:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { getSecret } from "jaypie";
|
|
71
|
+
|
|
72
|
+
// Fetch by exact AWS secret name
|
|
73
|
+
const secret = await getSecret("my-project/production/api-key");
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Note: `getSecret` requires `AWS_SESSION_TOKEN` and always calls Secrets Manager. Prefer `getEnvSecret` for typical use cases.
|
|
77
|
+
|
|
39
78
|
## Creating Secrets
|
|
40
79
|
|
|
41
80
|
### Via CDK
|
|
@@ -86,7 +125,7 @@ aws secretsmanager create-secret \
|
|
|
86
125
|
Retrieve in code:
|
|
87
126
|
|
|
88
127
|
```typescript
|
|
89
|
-
const credentialsJson = await
|
|
128
|
+
const credentialsJson = await getEnvSecret("DB_CREDENTIALS");
|
|
90
129
|
const credentials = JSON.parse(credentialsJson);
|
|
91
130
|
```
|
|
92
131
|
|
|
@@ -96,10 +135,10 @@ Secrets are cached by default to reduce API calls:
|
|
|
96
135
|
|
|
97
136
|
```typescript
|
|
98
137
|
// First call: fetches from Secrets Manager
|
|
99
|
-
const key1 = await
|
|
138
|
+
const key1 = await getEnvSecret("API_KEY");
|
|
100
139
|
|
|
101
140
|
// Second call: returns cached value
|
|
102
|
-
const key2 = await
|
|
141
|
+
const key2 = await getEnvSecret("API_KEY");
|
|
103
142
|
```
|
|
104
143
|
|
|
105
144
|
Cache is scoped to Lambda execution context (warm starts reuse cache).
|
|
@@ -125,19 +164,16 @@ secret.addRotationSchedule("Rotation", {
|
|
|
125
164
|
|
|
126
165
|
## Local Development
|
|
127
166
|
|
|
128
|
-
For local development,
|
|
167
|
+
For local development, set environment variables directly:
|
|
129
168
|
|
|
130
169
|
```bash
|
|
131
170
|
# .env.local (not committed)
|
|
171
|
+
ANTHROPIC_API_KEY=sk-ant-test123
|
|
132
172
|
MONGODB_URI=mongodb://localhost:27017/dev
|
|
133
173
|
API_KEY=test_key_123
|
|
134
174
|
```
|
|
135
175
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
const mongoUri = process.env.MONGODB_URI || await getSecret(process.env.SECRET_MONGODB_URI);
|
|
140
|
-
```
|
|
176
|
+
`getEnvSecret` automatically returns these values without AWS calls since there's no `SECRET_` prefix.
|
|
141
177
|
|
|
142
178
|
## IAM Permissions
|
|
143
179
|
|
|
@@ -153,3 +189,23 @@ lambdaFunction.addToRolePolicy(new PolicyStatement({
|
|
|
153
189
|
}));
|
|
154
190
|
```
|
|
155
191
|
|
|
192
|
+
## Testing
|
|
193
|
+
|
|
194
|
+
Mock secret functions in tests:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { getEnvSecret } from "@jaypie/testkit/mock";
|
|
198
|
+
import { vi } from "vitest";
|
|
199
|
+
|
|
200
|
+
vi.mock("@jaypie/aws");
|
|
201
|
+
|
|
202
|
+
describe("Handler", () => {
|
|
203
|
+
it("uses API key from secrets", async () => {
|
|
204
|
+
vi.mocked(getEnvSecret).mockResolvedValue("test-api-key");
|
|
205
|
+
|
|
206
|
+
const result = await handler();
|
|
207
|
+
|
|
208
|
+
expect(getEnvSecret).toHaveBeenCalledWith("API_KEY");
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
```
|
package/skills/skills.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description:
|
|
3
|
+
related:
|
|
4
|
+
agents: Prompts to improve agent adoption in AGENTS.md, CLAUDE.md, etc.
|
|
5
|
+
index: All available skills
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Jaypie Skills
|
|
9
|
+
|
|
10
|
+
- Instruct Jaypie styles, techniques, and traditions
|
|
11
|
+
- Written for agents
|
|
12
|
+
- Balance brevity and rigor
|
|
13
|
+
|
|
14
|
+
Look up skills by their "alias:"
|
|
15
|
+
`mcp__jaypie__skills(index)`
|
|
16
|
+
|
|
17
|
+
## Essentials
|
|
18
|
+
|
|
19
|
+
Contents: index, releasenotes
|
|
20
|
+
Development: documentation, errors, logs, mocks, style, tests
|
|
21
|
+
Infrastructure: aws, cdk, cicd, datadog, dns, dynamodb, secrets, variables
|
|
22
|
+
Patterns: fabric, models, services, vocabulary
|
|
23
|
+
Meta: issues, jaypie, skills, tools
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: AWS MCP tools for Lambda, S3, SQS, CloudWatch, Step Functions, CloudFormation
|
|
3
|
+
related: aws, tools, tools-dynamodb
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AWS MCP Tools
|
|
7
|
+
|
|
8
|
+
Tools for interacting with AWS services via the Jaypie MCP. Uses your local AWS credentials.
|
|
9
|
+
|
|
10
|
+
## Lambda Functions
|
|
11
|
+
|
|
12
|
+
| Tool | Description |
|
|
13
|
+
|------|-------------|
|
|
14
|
+
| `aws_lambda_list_functions` | List functions with optional prefix filter |
|
|
15
|
+
| `aws_lambda_get_function` | Get function configuration and details |
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
# List all functions
|
|
19
|
+
aws_lambda_list_functions
|
|
20
|
+
|
|
21
|
+
# Filter by prefix
|
|
22
|
+
aws_lambda_list_functions --prefix "my-api"
|
|
23
|
+
|
|
24
|
+
# Get function details
|
|
25
|
+
aws_lambda_get_function --functionName "my-api-handler"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Step Functions
|
|
29
|
+
|
|
30
|
+
| Tool | Description |
|
|
31
|
+
|------|-------------|
|
|
32
|
+
| `aws_stepfunctions_list_executions` | List executions for a state machine |
|
|
33
|
+
| `aws_stepfunctions_stop_execution` | Stop a running execution |
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
# List recent executions
|
|
37
|
+
aws_stepfunctions_list_executions --stateMachineArn "arn:aws:states:..."
|
|
38
|
+
|
|
39
|
+
# Stop a running execution
|
|
40
|
+
aws_stepfunctions_stop_execution --executionArn "arn:aws:states:..."
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## CloudWatch Logs
|
|
44
|
+
|
|
45
|
+
| Tool | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `aws_logs_filter_log_events` | Search logs with patterns and time ranges |
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
# Search for errors in Lambda logs
|
|
51
|
+
aws_logs_filter_log_events --logGroupName "/aws/lambda/my-function" --filterPattern "ERROR"
|
|
52
|
+
|
|
53
|
+
# Search with time range
|
|
54
|
+
aws_logs_filter_log_events --logGroupName "/aws/lambda/my-function" --startTime "2024-01-15T10:00:00Z"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## S3
|
|
58
|
+
|
|
59
|
+
| Tool | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `aws_s3_list_objects` | List bucket objects with prefix filtering |
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
# List all objects
|
|
65
|
+
aws_s3_list_objects --bucket "my-bucket"
|
|
66
|
+
|
|
67
|
+
# Filter by prefix
|
|
68
|
+
aws_s3_list_objects --bucket "my-bucket" --prefix "uploads/"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## SQS
|
|
72
|
+
|
|
73
|
+
| Tool | Description |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| `aws_sqs_list_queues` | List queues with prefix filter |
|
|
76
|
+
| `aws_sqs_get_queue_attributes` | Get queue attributes including message counts |
|
|
77
|
+
| `aws_sqs_receive_message` | Peek at queue messages (does not delete) |
|
|
78
|
+
| `aws_sqs_purge_queue` | Delete all messages (irreversible) |
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
# List queues
|
|
82
|
+
aws_sqs_list_queues --prefix "my-app"
|
|
83
|
+
|
|
84
|
+
# Check queue depth
|
|
85
|
+
aws_sqs_get_queue_attributes --queueUrl "https://sqs..."
|
|
86
|
+
|
|
87
|
+
# Peek at messages
|
|
88
|
+
aws_sqs_receive_message --queueUrl "https://sqs..." --maxNumberOfMessages 5
|
|
89
|
+
|
|
90
|
+
# Purge queue (careful!)
|
|
91
|
+
aws_sqs_purge_queue --queueUrl "https://sqs..."
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## CloudFormation
|
|
95
|
+
|
|
96
|
+
| Tool | Description |
|
|
97
|
+
|------|-------------|
|
|
98
|
+
| `aws_cloudformation_describe_stack` | Get stack details, outputs, and status |
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
# Get stack details
|
|
102
|
+
aws_cloudformation_describe_stack --stackName "MyStack"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Credential Management
|
|
106
|
+
|
|
107
|
+
Tools use the host's AWS credential chain:
|
|
108
|
+
1. Environment variables (`AWS_ACCESS_KEY_ID`, etc.)
|
|
109
|
+
2. `~/.aws/credentials` and `~/.aws/config`
|
|
110
|
+
3. SSO sessions via `aws sso login`
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
# List available profiles
|
|
114
|
+
aws_list_profiles
|
|
115
|
+
|
|
116
|
+
# Use a specific profile (supported on all tools)
|
|
117
|
+
aws_lambda_list_functions --profile production --region us-west-2
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Environment Variables
|
|
121
|
+
|
|
122
|
+
| Variable | Description |
|
|
123
|
+
|----------|-------------|
|
|
124
|
+
| `AWS_PROFILE` | Default profile |
|
|
125
|
+
| `AWS_REGION` | Default region |
|
|
126
|
+
|
|
127
|
+
## Common Patterns
|
|
128
|
+
|
|
129
|
+
### Debug Lambda Issues
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
# Check function config
|
|
133
|
+
aws_lambda_get_function --functionName "my-function"
|
|
134
|
+
|
|
135
|
+
# Search recent logs
|
|
136
|
+
aws_logs_filter_log_events --logGroupName "/aws/lambda/my-function" --filterPattern "ERROR"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Check Queue Health
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
# Get queue depth
|
|
143
|
+
aws_sqs_get_queue_attributes --queueUrl "https://..."
|
|
144
|
+
|
|
145
|
+
# Peek at messages
|
|
146
|
+
aws_sqs_receive_message --queueUrl "https://..." --maxNumberOfMessages 5
|
|
147
|
+
```
|
|
148
|
+
|