@jaypie/mcp 0.2.0 → 0.2.2

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
@@ -797,7 +797,7 @@ async function searchDatadogRum(credentials, options = {}, logger = nullLogger)
797
797
  });
798
798
  }
799
799
 
800
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.0"
800
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.2#fd3043b3"
801
801
  ;
802
802
  const __filename$1 = fileURLToPath(import.meta.url);
803
803
  const __dirname$1 = path.dirname(__filename$1);
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://github.com/finlaysonstudio/jaypie"
7
+ "url": "git+https://github.com/finlaysonstudio/jaypie.git"
8
8
  },
9
9
  "license": "MIT",
10
10
  "author": "Finlayson Studio",
@@ -0,0 +1,103 @@
1
+ ---
2
+ description: development utilities bundle for Jaypie repositories
3
+ ---
4
+
5
+ # Jaypie Repokit
6
+
7
+ Essential development utilities bundled for Jaypie repositories. Provides common tools needed for build scripts, development workflows, and repository maintenance.
8
+
9
+ ## Installation
10
+
11
+ ```sh
12
+ npm install --save-dev @jaypie/repokit
13
+ ```
14
+
15
+ ## Exported Utilities
16
+
17
+ ### dotenv
18
+
19
+ Re-exports everything from `dotenv` for environment variable management.
20
+
21
+ ```typescript
22
+ import { config } from "@jaypie/repokit";
23
+
24
+ config(); // Load .env file
25
+ ```
26
+
27
+ ### rimraf
28
+
29
+ Re-exports `rimraf` for cross-platform file deletion.
30
+
31
+ ```typescript
32
+ import { rimraf } from "@jaypie/repokit";
33
+
34
+ await rimraf("./dist");
35
+ ```
36
+
37
+ ## CLI Tools (via npx)
38
+
39
+ The package includes CLI tools as dependencies that can be run via npx or in package.json scripts:
40
+
41
+ ### env-cmd
42
+
43
+ Run commands with environment variables from a file.
44
+
45
+ ```json
46
+ {
47
+ "scripts": {
48
+ "start:dev": "env-cmd -f .env.development node server.js"
49
+ }
50
+ }
51
+ ```
52
+
53
+ ### sort-package-json
54
+
55
+ Sort package.json files for consistent formatting.
56
+
57
+ ```json
58
+ {
59
+ "scripts": {
60
+ "format:package": "sort-package-json ./package.json"
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### tsx
66
+
67
+ Run TypeScript files directly without compilation.
68
+
69
+ ```json
70
+ {
71
+ "scripts": {
72
+ "bin:script": "tsx scripts/my-script.ts"
73
+ }
74
+ }
75
+ ```
76
+
77
+ ## Common Usage Patterns
78
+
79
+ ### Build Scripts
80
+
81
+ ```json
82
+ {
83
+ "scripts": {
84
+ "clean": "rimraf ./dist",
85
+ "format:package": "sort-package-json ./package.json",
86
+ "bin:setup": "tsx scripts/setup.ts"
87
+ }
88
+ }
89
+ ```
90
+
91
+ ### Environment Management
92
+
93
+ ```typescript
94
+ // scripts/deploy.ts
95
+ import { config } from "@jaypie/repokit";
96
+
97
+ config({ path: ".env.production" });
98
+ console.log(process.env.API_KEY);
99
+ ```
100
+
101
+ ## Why Use Repokit
102
+
103
+ Instead of installing `dotenv`, `rimraf`, `env-cmd`, `sort-package-json`, and `tsx` individually in each package, install `@jaypie/repokit` once to get all essential development utilities. This ensures consistent versions across all Jaypie repositories.
@@ -0,0 +1,451 @@
1
+ ---
2
+ description: Complete guide to using Jaypie Vocabulary for type coercion, service handlers, and Commander CLI integration
3
+ ---
4
+
5
+ # Jaypie Vocabulary Package
6
+
7
+ Jaypie Vocabulary (`@jaypie/vocabulary`) provides type coercion utilities and service handler patterns for consistent input handling across Jaypie applications. It includes adapters for integrating service handlers with Commander.js CLIs.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @jaypie/vocabulary
13
+ # For CLI integration:
14
+ npm install commander
15
+ ```
16
+
17
+ ## Core Concepts
18
+
19
+ ### Design Philosophy
20
+
21
+ Vocabulary follows the "Fabric" philosophy:
22
+ - **Smooth, pliable** - Things that feel right should work
23
+ - **Catch bad passes** - Invalid inputs throw clear errors
24
+
25
+ This means `"true"` works where `true` is expected, `"42"` works where `42` is expected, and invalid conversions fail fast with `BadRequestError`.
26
+
27
+ ## serviceHandler
28
+
29
+ Factory function that creates validated service endpoints with automatic type coercion.
30
+
31
+ ### Basic Usage
32
+
33
+ ```typescript
34
+ import { serviceHandler } from "@jaypie/vocabulary";
35
+
36
+ const divisionHandler = serviceHandler({
37
+ alias: "division",
38
+ description: "Divides two numbers",
39
+ input: {
40
+ numerator: {
41
+ type: Number,
42
+ default: 12,
43
+ description: "Number on top",
44
+ },
45
+ denominator: {
46
+ type: Number,
47
+ default: 3,
48
+ description: "Number on bottom",
49
+ validate: (value) => value !== 0,
50
+ },
51
+ },
52
+ service: ({ numerator, denominator }) => numerator / denominator,
53
+ });
54
+
55
+ await divisionHandler(); // → 4
56
+ await divisionHandler({ numerator: 24 }); // → 8
57
+ await divisionHandler({ numerator: "14", denominator: "7" }); // → 2 (coerced)
58
+ await divisionHandler('{"numerator": "18"}'); // → 6 (JSON parsed)
59
+ ```
60
+
61
+ ### Handler Properties
62
+
63
+ Config properties are attached directly to the handler for introspection:
64
+
65
+ ```typescript
66
+ const handler = serviceHandler({
67
+ alias: "greet",
68
+ description: "Greet a user",
69
+ input: { name: { type: String } },
70
+ service: ({ name }) => `Hello, ${name}!`,
71
+ });
72
+
73
+ handler.alias; // "greet"
74
+ handler.description; // "Greet a user"
75
+ handler.input; // { name: { type: String } }
76
+ ```
77
+
78
+ ### Input Field Definition
79
+
80
+ | Property | Type | Description |
81
+ |----------|------|-------------|
82
+ | `type` | `CoercionType` | Required. The target type for coercion |
83
+ | `default` | `unknown` | Default value if not provided |
84
+ | `description` | `string` | Field description (used in CLI help) |
85
+ | `required` | `boolean` | Whether field is required (default: true unless default set) |
86
+ | `validate` | `function \| RegExp \| array` | Validation after coercion |
87
+ | `flag` | `string` | Override long flag name for Commander.js |
88
+ | `letter` | `string` | Short switch letter for Commander.js |
89
+
90
+ ### Validation-Only Mode
91
+
92
+ When no `service` function is provided, the handler returns the processed input:
93
+
94
+ ```typescript
95
+ const validateUser = serviceHandler({
96
+ input: {
97
+ age: { type: Number, validate: (v) => v >= 18 },
98
+ email: { type: /^[^@]+@[^@]+\.[^@]+$/ },
99
+ role: { type: ["admin", "user", "guest"], default: "user" },
100
+ },
101
+ });
102
+
103
+ await validateUser({ age: "25", email: "bob@example.com" });
104
+ // → { age: 25, email: "bob@example.com", role: "user" }
105
+ ```
106
+
107
+ ## Type Coercion
108
+
109
+ ### Supported Types
110
+
111
+ | Type | Aliases | Description |
112
+ |------|---------|-------------|
113
+ | `String` | `"string"`, `""` | String coercion |
114
+ | `Number` | `"number"` | Number coercion |
115
+ | `Boolean` | `"boolean"` | Boolean coercion |
116
+ | `Array` | `"array"`, `[]` | Array coercion |
117
+ | `Object` | `"object"`, `{}` | Object coercion |
118
+ | `[String]` | `[""]` | Typed array of strings |
119
+ | `[Number]` | - | Typed array of numbers |
120
+ | `[Boolean]` | - | Typed array of booleans |
121
+ | `[Object]` | `[{}]` | Typed array of objects |
122
+ | `/regex/` | - | String with regex validation |
123
+ | `["a", "b"]` | - | Validated string (must match) |
124
+ | `[1, 2, 3]` | - | Validated number (must match) |
125
+
126
+ ### Coercion Examples
127
+
128
+ ```typescript
129
+ import { coerce } from "@jaypie/vocabulary";
130
+
131
+ // Boolean coercion
132
+ coerce("true", Boolean); // → true
133
+ coerce("false", Boolean); // → false
134
+ coerce(1, Boolean); // → true
135
+ coerce(0, Boolean); // → false
136
+
137
+ // Number coercion
138
+ coerce("42", Number); // → 42
139
+ coerce("true", Number); // → 1
140
+ coerce("false", Number); // → 0
141
+
142
+ // String coercion
143
+ coerce(true, String); // → "true"
144
+ coerce(42, String); // → "42"
145
+
146
+ // Array coercion
147
+ coerce("1,2,3", [Number]); // → [1, 2, 3]
148
+ coerce("a\tb\tc", [String]); // → ["a", "b", "c"]
149
+ coerce([1, 2], [String]); // → ["1", "2"]
150
+
151
+ // Unwrapping
152
+ coerce({ value: "42" }, Number); // → 42
153
+ coerce(["true"], Boolean); // → true
154
+ coerce('{"value": 5}', Number); // → 5
155
+ ```
156
+
157
+ ### RegExp Type Shorthand
158
+
159
+ A bare RegExp coerces to String and validates:
160
+
161
+ ```typescript
162
+ const handler = serviceHandler({
163
+ input: {
164
+ email: { type: /^[^@]+@[^@]+\.[^@]+$/ },
165
+ },
166
+ service: ({ email }) => email,
167
+ });
168
+
169
+ await handler({ email: "bob@example.com" }); // ✓
170
+ await handler({ email: "invalid" }); // ✗ BadRequestError
171
+ ```
172
+
173
+ ### Validated Type Shorthand
174
+
175
+ Arrays of literals validate against allowed values:
176
+
177
+ ```typescript
178
+ // String validation
179
+ input: {
180
+ currency: { type: ["usd", "eur", "gbp"] }, // Must be one of these
181
+ pattern: { type: [/^test-/, "special"] }, // Matches regex OR equals "special"
182
+ }
183
+
184
+ // Number validation
185
+ input: {
186
+ priority: { type: [1, 2, 3, 4, 5] }, // Must be 1-5
187
+ }
188
+ ```
189
+
190
+ ## Commander.js Integration
191
+
192
+ ### registerServiceCommand (Recommended)
193
+
194
+ The simplest way to register a service handler as a Commander command:
195
+
196
+ ```typescript
197
+ import { Command } from "commander";
198
+ import { serviceHandler } from "@jaypie/vocabulary";
199
+ import { registerServiceCommand } from "@jaypie/vocabulary/commander";
200
+
201
+ const handler = serviceHandler({
202
+ alias: "greet",
203
+ description: "Greet a user",
204
+ input: {
205
+ userName: { type: String, flag: "user", letter: "u" },
206
+ loud: { type: Boolean, letter: "l", default: false },
207
+ },
208
+ service: ({ loud, userName }) => {
209
+ const greeting = `Hello, ${userName}!`;
210
+ console.log(loud ? greeting.toUpperCase() : greeting);
211
+ },
212
+ });
213
+
214
+ const program = new Command();
215
+ registerServiceCommand({ handler, program });
216
+ program.parse();
217
+ // Usage: greet --user Alice -l
218
+ // Output: HELLO, ALICE!
219
+ ```
220
+
221
+ ### registerServiceCommand Options
222
+
223
+ | Option | Type | Description |
224
+ |--------|------|-------------|
225
+ | `handler` | `ServiceHandlerFunction` | Required. The service handler |
226
+ | `program` | `Command` | Required. Commander program or command |
227
+ | `name` | `string` | Override command name (default: handler.alias) |
228
+ | `description` | `string` | Override description (default: handler.description) |
229
+ | `exclude` | `string[]` | Field names to exclude from options |
230
+ | `overrides` | `Record<string, override>` | Per-field option overrides |
231
+
232
+ ### Input Flag and Letter Properties
233
+
234
+ Define CLI flags directly in input definitions:
235
+
236
+ ```typescript
237
+ input: {
238
+ userName: {
239
+ type: String,
240
+ flag: "user", // Long flag: --user (instead of --user-name)
241
+ letter: "u", // Short flag: -u
242
+ description: "User name to greet",
243
+ },
244
+ verbose: {
245
+ type: Boolean,
246
+ letter: "v", // -v
247
+ },
248
+ }
249
+ // Generates: --user <userName>, -u and --verbose, -v
250
+ ```
251
+
252
+ ### Manual Integration
253
+
254
+ For more control, use `createCommanderOptions` and `parseCommanderOptions`:
255
+
256
+ ```typescript
257
+ import { Command } from "commander";
258
+ import { serviceHandler } from "@jaypie/vocabulary";
259
+ import {
260
+ createCommanderOptions,
261
+ parseCommanderOptions,
262
+ } from "@jaypie/vocabulary/commander";
263
+
264
+ const handler = serviceHandler({
265
+ input: {
266
+ userName: { type: String, description: "User name" },
267
+ maxRetries: { type: Number, default: 3 },
268
+ verbose: { type: Boolean },
269
+ },
270
+ service: (input) => console.log(input),
271
+ });
272
+
273
+ const program = new Command();
274
+
275
+ // Create options from handler input
276
+ const { options } = createCommanderOptions(handler.input, {
277
+ exclude: ["internalField"],
278
+ overrides: {
279
+ userName: { short: "u", description: "Override description" },
280
+ },
281
+ });
282
+ options.forEach((opt) => program.addOption(opt));
283
+
284
+ // Wire up action
285
+ program.action(async (opts) => {
286
+ const input = parseCommanderOptions(opts, { input: handler.input });
287
+ await handler(input);
288
+ });
289
+
290
+ program.parse();
291
+ ```
292
+
293
+ ### Boolean Flag Behavior
294
+
295
+ Commander.js automatically handles boolean flags:
296
+ - `--verbose` sets to `true`
297
+ - `--no-verbose` sets to `false` (for flags with `default: true`)
298
+
299
+ ## Complete CLI Example
300
+
301
+ ```typescript
302
+ // src/commands/evaluate.ts
303
+ import { Command } from "commander";
304
+ import { serviceHandler } from "@jaypie/vocabulary";
305
+ import { registerServiceCommand } from "@jaypie/vocabulary/commander";
306
+
307
+ export const evaluateHandler = serviceHandler({
308
+ alias: "evaluate",
309
+ description: "Run an evaluation job",
310
+ input: {
311
+ jobId: {
312
+ type: String,
313
+ flag: "job",
314
+ letter: "j",
315
+ description: "Job identifier",
316
+ },
317
+ priority: {
318
+ type: [1, 2, 3, 4, 5],
319
+ default: 3,
320
+ letter: "p",
321
+ description: "Job priority (1-5)",
322
+ },
323
+ tags: {
324
+ type: [String],
325
+ letter: "t",
326
+ required: false,
327
+ description: "Tags to apply",
328
+ },
329
+ dryRun: {
330
+ type: Boolean,
331
+ letter: "d",
332
+ default: false,
333
+ description: "Run without executing",
334
+ },
335
+ },
336
+ service: async ({ dryRun, jobId, priority, tags }) => {
337
+ console.log(`Running job ${jobId} with priority ${priority}`);
338
+ if (tags?.length) console.log(`Tags: ${tags.join(", ")}`);
339
+ if (dryRun) {
340
+ console.log("(dry run - no changes made)");
341
+ return;
342
+ }
343
+ // Execute job...
344
+ },
345
+ });
346
+
347
+ export function evaluateCommand(program: Command): Command {
348
+ registerServiceCommand({ handler: evaluateHandler, program });
349
+ return program;
350
+ }
351
+ ```
352
+
353
+ Usage:
354
+ ```bash
355
+ # Required job, default priority
356
+ cli evaluate --job abc123
357
+
358
+ # With all options
359
+ cli evaluate -j abc123 -p 1 -t urgent -t critical --dry-run
360
+
361
+ # Help
362
+ cli evaluate --help
363
+ ```
364
+
365
+ ## TypeScript Types
366
+
367
+ ```typescript
368
+ import type {
369
+ // Coercion types
370
+ CoercionType,
371
+ ScalarType,
372
+ CompositeType,
373
+ TypedArrayType,
374
+ ValidatedStringType,
375
+ ValidatedNumberType,
376
+ RegExpType,
377
+ ArrayElementType,
378
+
379
+ // Service handler types
380
+ InputFieldDefinition,
381
+ ValidateFunction,
382
+ ServiceFunction,
383
+ ServiceHandlerConfig,
384
+ ServiceHandlerFunction,
385
+ } from "@jaypie/vocabulary";
386
+
387
+ import type {
388
+ // Commander adapter types
389
+ CommanderOptionOverride,
390
+ CreateCommanderOptionsConfig,
391
+ CreateCommanderOptionsResult,
392
+ ParseCommanderOptionsConfig,
393
+ RegisterServiceCommandConfig,
394
+ RegisterServiceCommandResult,
395
+ } from "@jaypie/vocabulary/commander";
396
+ ```
397
+
398
+ ## Exports
399
+
400
+ ### Main Export (`@jaypie/vocabulary`)
401
+
402
+ ```typescript
403
+ // Coercion functions
404
+ export {
405
+ coerce,
406
+ coerceFromArray,
407
+ coerceFromObject,
408
+ coerceToArray,
409
+ coerceToBoolean,
410
+ coerceToNumber,
411
+ coerceToObject,
412
+ coerceToString,
413
+ } from "./coerce.js";
414
+
415
+ // Service Handler
416
+ export { serviceHandler } from "./serviceHandler.js";
417
+
418
+ // Commander namespace
419
+ export * as commander from "./commander/index.js";
420
+
421
+ // Version
422
+ export const VOCABULARY_VERSION: string;
423
+ ```
424
+
425
+ ### Commander Export (`@jaypie/vocabulary/commander`)
426
+
427
+ ```typescript
428
+ export { createCommanderOptions } from "./createCommanderOptions.js";
429
+ export { parseCommanderOptions } from "./parseCommanderOptions.js";
430
+ export { registerServiceCommand } from "./registerServiceCommand.js";
431
+ ```
432
+
433
+ ## Error Handling
434
+
435
+ Invalid coercions throw `BadRequestError` from `@jaypie/errors`:
436
+
437
+ ```typescript
438
+ import { BadRequestError } from "@jaypie/errors";
439
+
440
+ // These throw BadRequestError:
441
+ await handler({ numerator: "not-a-number" }); // Cannot coerce to Number
442
+ await handler({ priority: 10 }); // Validation fails (not in [1,2,3,4,5])
443
+ await handler({}); // Missing required field
444
+ ```
445
+
446
+ ## Integration with Other Packages
447
+
448
+ Vocabulary is designed to be consumed by:
449
+ - **`@jaypie/lambda`** - Lambda handler input processing
450
+ - **`@jaypie/express`** - Express route input validation
451
+ - **CLI packages** - Commander.js integration via the commander adapter