@jaypie/mcp 0.3.0 → 0.3.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/index.js CHANGED
@@ -1208,7 +1208,7 @@ async function purgeSQSQueue(options, logger = nullLogger) {
1208
1208
  return executeAwsCommand("sqs", "purge-queue", ["--queue-url", options.queueUrl], { profile: options.profile, region: options.region }, logger);
1209
1209
  }
1210
1210
 
1211
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.3.0#8cd307b1"
1211
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.3.1#4e71c6ce"
1212
1212
  ;
1213
1213
  const __filename$1 = fileURLToPath(import.meta.url);
1214
1214
  const __dirname$1 = path.dirname(__filename$1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -106,7 +106,6 @@ For streaming responses (SSE, real-time updates), use `createLambdaStreamHandler
106
106
 
107
107
  ```typescript
108
108
  import { JaypieExpressLambda, JaypieDistribution } from "@jaypie/constructs";
109
- import * as lambda from "aws-cdk-lib/aws-lambda";
110
109
 
111
110
  // Create Lambda (handler uses createLambdaStreamHandler internally)
112
111
  const streamingApi = new JaypieExpressLambda(this, "StreamingApi", {
@@ -114,10 +113,10 @@ const streamingApi = new JaypieExpressLambda(this, "StreamingApi", {
114
113
  handler: "index.handler",
115
114
  });
116
115
 
117
- // Use with CloudFront and RESPONSE_STREAM invoke mode
116
+ // Use with CloudFront and streaming enabled
118
117
  new JaypieDistribution(this, "Distribution", {
119
118
  handler: streamingApi,
120
- invokeMode: lambda.InvokeMode.RESPONSE_STREAM,
119
+ streaming: true,
121
120
  host: "api.example.com",
122
121
  zone: "example.com",
123
122
  });
@@ -135,13 +134,13 @@ const streamingLambda = new JaypieLambda(this, "StreamingFunction", {
135
134
 
136
135
  const functionUrl = streamingLambda.addFunctionUrl({
137
136
  authType: FunctionUrlAuthType.NONE,
138
- invokeMode: InvokeMode.RESPONSE_STREAM,
137
+ invokeMode: InvokeMode.RESPONSE_STREAM, // Direct Function URL still uses InvokeMode
139
138
  });
140
139
 
141
140
  new cdk.CfnOutput(this, "StreamingUrl", { value: functionUrl.url });
142
141
  ```
143
142
 
144
- Note: Streaming requires Lambda Function URLs (not API Gateway). `JaypieDistribution` uses Function URLs by default.
143
+ Note: Streaming requires Lambda Function URLs (not API Gateway). `JaypieDistribution` uses Function URLs by default and accepts `streaming: true` for a cleaner API.
145
144
 
146
145
  ### Stack Types
147
146
 
@@ -482,6 +482,14 @@ streamingLambda.addFunctionUrl({
482
482
  authType: FunctionUrlAuthType.NONE, // or AWS_IAM for auth
483
483
  invokeMode: InvokeMode.RESPONSE_STREAM,
484
484
  });
485
+
486
+ // Or use JaypieDistribution with streaming: true for CloudFront integration
487
+ new JaypieDistribution(this, "Distribution", {
488
+ handler: streamingLambda,
489
+ streaming: true,
490
+ host: "api.example.com",
491
+ zone: "example.com",
492
+ });
485
493
  ```
486
494
 
487
495
  ### Error Handling in Streams
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Complete guide to streaming in Jaypie - Lambda, Express, and SSE patterns
2
+ description: Complete guide to streaming in Jaypie - Lambda, Express, SSE, and NLJSON patterns
3
3
  globs: packages/express/**, packages/lambda/**, packages/aws/**
4
4
  ---
5
5
 
@@ -7,6 +7,23 @@ globs: packages/express/**, packages/lambda/**, packages/aws/**
7
7
 
8
8
  Jaypie provides three distinct streaming patterns for different deployment scenarios. This guide explains when to use each approach and how to implement streaming correctly.
9
9
 
10
+ ## Stream Formats
11
+
12
+ Jaypie supports two stream output formats:
13
+
14
+ | Format | Content-Type | Use Case |
15
+ |--------|--------------|----------|
16
+ | SSE (default) | `text/event-stream` | Browser EventSource, real-time UI updates |
17
+ | NLJSON | `application/x-ndjson` | Machine-to-machine, log processing |
18
+
19
+ ### Format Comparison
20
+
21
+ | Aspect | SSE | NLJSON |
22
+ |--------|-----|--------|
23
+ | Data format | `event: <type>\ndata: {...}\n\n` | `{...}\n` |
24
+ | Error format | `event: error\ndata: {...}\n\n` | `{"error":{...}}\n` |
25
+ | Browser support | Native EventSource API | Requires manual parsing |
26
+
10
27
  ## Quick Reference
11
28
 
12
29
  | Handler | Package | Express Required | Use Case |
@@ -31,8 +48,11 @@ All streaming utilities are exported from `@jaypie/aws` and re-exported through
31
48
  | `createExpressStream(stream, res)` | Pipe async iterable to Express response with SSE headers |
32
49
  | `JaypieStream` | Wrapper class with `.toLambda()` and `.toExpress()` methods |
33
50
  | `createJaypieStream(source)` | Factory function for JaypieStream |
34
- | `formatSSE(chunk)` | Format a chunk as SSE event string |
35
- | `streamToSSE(stream)` | Convert async iterable to SSE-formatted strings |
51
+ | `formatSse(chunk)` | Format a chunk as SSE event string |
52
+ | `formatNljson(chunk)` | Format a chunk as NLJSON string |
53
+ | `formatStreamError(errorBody, format)` | Format error based on stream format |
54
+ | `getContentTypeForFormat(format)` | Get content type for stream format |
55
+ | `streamToSse(stream)` | Convert async iterable to SSE-formatted strings |
36
56
 
37
57
  ### Types
38
58
 
@@ -40,8 +60,9 @@ All streaming utilities are exported from `@jaypie/aws` and re-exported through
40
60
  import type {
41
61
  ExpressStreamResponse,
42
62
  LambdaStreamWriter,
43
- SSEEvent,
63
+ SseEvent,
44
64
  StreamChunk,
65
+ StreamFormat, // "sse" | "nljson"
45
66
  } from "jaypie";
46
67
  ```
47
68
 
@@ -49,13 +70,16 @@ import type {
49
70
 
50
71
  Use for pure Lambda functions without Express. Requires AWS Lambda Response Streaming via Function URL.
51
72
 
73
+ **Note:** `lambdaStreamHandler` automatically wraps with `awslambda.streamifyResponse()` in the Lambda runtime. You no longer need to wrap manually.
74
+
52
75
  ### Basic Usage
53
76
 
54
77
  ```typescript
55
78
  import { lambdaStreamHandler } from "jaypie";
56
79
  import type { StreamHandlerContext } from "@jaypie/lambda";
57
80
 
58
- const streamWorker = lambdaStreamHandler(
81
+ // Auto-wrapped with awslambda.streamifyResponse() in Lambda runtime
82
+ export const handler = lambdaStreamHandler(
59
83
  async (event: unknown, context: StreamHandlerContext) => {
60
84
  const { responseStream } = context;
61
85
 
@@ -70,13 +94,18 @@ const streamWorker = lambdaStreamHandler(
70
94
  },
71
95
  {
72
96
  name: "streamWorker",
73
- contentType: "text/event-stream",
74
97
  }
75
98
  );
99
+ ```
76
100
 
77
- // Wrap with AWS streamifyResponse for Lambda
78
- declare const awslambda: { streamifyResponse: <T>(handler: T) => T };
79
- export const handler = awslambda.streamifyResponse(streamWorker);
101
+ ### With Format Option
102
+
103
+ ```typescript
104
+ // SSE format (default)
105
+ export const sseHandler = lambdaStreamHandler(myHandler, { format: "sse" });
106
+
107
+ // NLJSON format
108
+ export const nljsonHandler = lambdaStreamHandler(myHandler, { format: "nljson" });
80
109
  ```
81
110
 
82
111
  ### With LLM Streaming
@@ -89,7 +118,8 @@ interface PromptEvent {
89
118
  prompt?: string;
90
119
  }
91
120
 
92
- const llmStreamHandler = lambdaStreamHandler(
121
+ // Auto-wrapped with awslambda.streamifyResponse() in Lambda runtime
122
+ export const handler = lambdaStreamHandler(
93
123
  async (event: PromptEvent, context: StreamHandlerContext) => {
94
124
  const llm = new Llm("anthropic");
95
125
  const stream = llm.stream(event.prompt || "Hello");
@@ -102,25 +132,23 @@ const llmStreamHandler = lambdaStreamHandler(
102
132
  secrets: ["ANTHROPIC_API_KEY"],
103
133
  }
104
134
  );
105
-
106
- declare const awslambda: { streamifyResponse: <T>(handler: T) => T };
107
- export const handler = awslambda.streamifyResponse(llmStreamHandler);
108
135
  ```
109
136
 
110
137
  ### Handler Options
111
138
 
112
139
  ```typescript
113
- import type { LambdaStreamHandlerOptions } from "@jaypie/lambda";
140
+ import type { LambdaStreamHandlerOptions, StreamFormat } from "@jaypie/lambda";
114
141
 
115
142
  const options: LambdaStreamHandlerOptions = {
116
143
  name: "myStreamHandler", // Handler name for logging
117
- contentType: "text/event-stream", // Response content type (default)
144
+ format: "sse", // Stream format: "sse" (default) or "nljson"
145
+ contentType: "text/event-stream", // Response content type (auto-set from format)
118
146
  chaos: "low", // Chaos testing level
119
147
  secrets: ["API_KEY"], // AWS secrets to load into process.env
120
148
  setup: [], // Setup function(s)
121
149
  teardown: [], // Teardown function(s)
122
150
  validate: [], // Validation function(s)
123
- throw: false, // Re-throw errors instead of SSE error
151
+ throw: false, // Re-throw errors instead of streaming error
124
152
  unavailable: false, // Return 503 if true
125
153
  };
126
154
  ```
@@ -137,11 +165,19 @@ const streamingLambda = new JaypieLambda(this, "StreamingFunction", {
137
165
  timeout: Duration.minutes(5),
138
166
  });
139
167
 
140
- // Enable Lambda Response Streaming
168
+ // For direct Function URL access:
141
169
  streamingLambda.addFunctionUrl({
142
170
  authType: FunctionUrlAuthType.NONE,
143
171
  invokeMode: InvokeMode.RESPONSE_STREAM,
144
172
  });
173
+
174
+ // Or use JaypieDistribution with streaming: true
175
+ new JaypieDistribution(this, "Distribution", {
176
+ handler: streamingLambda,
177
+ streaming: true,
178
+ host: "api.example.com",
179
+ zone: "example.com",
180
+ });
145
181
  ```
146
182
 
147
183
  ## Pattern 2: expressStreamHandler
@@ -180,14 +216,25 @@ const llmStreamRoute = expressStreamHandler(async (req: Request, res: Response)
180
216
  app.post("/chat", llmStreamRoute);
181
217
  ```
182
218
 
219
+ ### With Format Option
220
+
221
+ ```typescript
222
+ // SSE format (default)
223
+ app.get("/stream-sse", expressStreamHandler(myHandler, { format: "sse" }));
224
+
225
+ // NLJSON format
226
+ app.get("/stream-nljson", expressStreamHandler(myHandler, { format: "nljson" }));
227
+ ```
228
+
183
229
  ### Handler Options
184
230
 
185
231
  ```typescript
186
- import type { ExpressStreamHandlerOptions } from "jaypie";
232
+ import type { ExpressStreamHandlerOptions, StreamFormat } from "jaypie";
187
233
 
188
234
  const options: ExpressStreamHandlerOptions = {
189
235
  name: "myStreamHandler", // Handler name for logging
190
- contentType: "text/event-stream", // Default SSE content type
236
+ format: "sse", // Stream format: "sse" (default) or "nljson"
237
+ contentType: "text/event-stream", // Response content type (auto-set from format)
191
238
  chaos: "low", // Chaos testing level
192
239
  secrets: ["API_KEY"], // Secrets to load
193
240
  setup: [], // Setup function(s)
@@ -296,17 +343,17 @@ for await (const sseEvent of stream.toSSE()) {
296
343
  ### Manual SSE Formatting
297
344
 
298
345
  ```typescript
299
- import { formatSSE } from "jaypie";
346
+ import { formatSse } from "jaypie";
300
347
 
301
348
  const chunk = { type: "message", content: "Hello" };
302
- const sseString = formatSSE(chunk);
349
+ const sseString = formatSse(chunk);
303
350
  // "event: message\ndata: {\"type\":\"message\",\"content\":\"Hello\"}\n\n"
304
351
  ```
305
352
 
306
353
  ### Converting Async Iterables
307
354
 
308
355
  ```typescript
309
- import { streamToSSE } from "jaypie";
356
+ import { streamToSse } from "jaypie";
310
357
 
311
358
  async function* myGenerator() {
312
359
  yield { type: "start", data: {} };
@@ -314,28 +361,36 @@ async function* myGenerator() {
314
361
  yield { type: "end", data: {} };
315
362
  }
316
363
 
317
- for await (const sseEvent of streamToSSE(myGenerator())) {
364
+ for await (const sseEvent of streamToSse(myGenerator())) {
318
365
  responseStream.write(sseEvent);
319
366
  }
320
367
  ```
321
368
 
322
369
  ## Error Handling
323
370
 
324
- Errors in streaming handlers are written as SSE error events:
371
+ Errors in streaming handlers are written to the stream in the configured format:
372
+
373
+ **SSE format (default):**
374
+ ```
375
+ event: error
376
+ data: {"errors":[{"status":500,"title":"Internal Error"}]}
325
377
 
326
- ```typescript
327
- // Format: event: error\ndata: {"errors":[{"status":500,"title":"Internal Error"}]}\n\n
378
+ ```
379
+
380
+ **NLJSON format:**
381
+ ```
382
+ {"error":{"errors":[{"status":500,"title":"Internal Error"}]}}
328
383
  ```
329
384
 
330
385
  For `lambdaStreamHandler`, set `throw: true` to re-throw errors instead of writing to stream:
331
386
 
332
387
  ```typescript
333
- const handler = lambdaStreamHandler(
388
+ export const handler = lambdaStreamHandler(
334
389
  async (event, context) => {
335
390
  throw new InternalError("Something went wrong");
336
391
  },
337
392
  {
338
- throw: true, // Re-throw instead of SSE error
393
+ throw: true, // Re-throw instead of streaming error
339
394
  }
340
395
  );
341
396
  ```
@@ -383,10 +438,13 @@ Use the Docker setup in `packages/express/docker/` for local Lambda streaming te
383
438
  ```typescript
384
439
  // From @jaypie/lambda
385
440
  import type {
441
+ AwsStreamingHandler,
442
+ LambdaHandler, // Wrapped handler type (after awslambda.streamifyResponse)
386
443
  LambdaStreamHandlerOptions,
387
- StreamHandlerContext,
444
+ RawStreamingHandler, // Alias for AwsStreamingHandler (for testing)
388
445
  ResponseStream,
389
- AwsStreamingHandler,
446
+ StreamFormat, // "sse" | "nljson" (re-exported from @jaypie/aws)
447
+ StreamHandlerContext,
390
448
  } from "@jaypie/lambda";
391
449
 
392
450
  // From @jaypie/express (or jaypie)
@@ -402,7 +460,8 @@ import type {
402
460
  import type {
403
461
  ExpressStreamResponse,
404
462
  LambdaStreamWriter,
405
- SSEEvent,
463
+ SseEvent,
406
464
  StreamChunk,
465
+ StreamFormat, // "sse" | "nljson"
407
466
  } from "jaypie";
408
467
  ```