@tigerdata/mcp-boilerplate 0.7.0 → 0.8.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.
package/dist/types.d.ts CHANGED
@@ -70,6 +70,18 @@ export interface McpFeatureFlags {
70
70
  disabledTools?: Set<string> | null;
71
71
  query?: ParsedQs;
72
72
  }
73
- export type InferSchema<T extends Record<string, z.ZodType>> = {
74
- [K in keyof T]: z.infer<T[K]>;
75
- };
73
+ type Flatten<T> = {
74
+ [K in keyof T]: T[K];
75
+ } & {};
76
+ type OptionalKeys<T extends Record<string, z.ZodType>> = {
77
+ [K in keyof T]: T[K] extends z.ZodOptional<z.ZodType> ? K : never;
78
+ }[keyof T];
79
+ type RequiredKeys<T extends Record<string, z.ZodType>> = {
80
+ [K in keyof T]: T[K] extends z.ZodOptional<z.ZodType> ? never : K;
81
+ }[keyof T];
82
+ export type InferSchema<T extends Record<string, z.ZodType>> = Flatten<{
83
+ [K in RequiredKeys<T>]: z.infer<T[K]>;
84
+ } & {
85
+ [K in OptionalKeys<T>]?: z.infer<T[K]>;
86
+ }>;
87
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,153 @@
1
+ import { describe, it, expect, expectTypeOf } from 'bun:test';
2
+ import { z } from 'zod';
3
+ describe('InferSchema', () => {
4
+ it('should infer required properties correctly', () => {
5
+ const schema = {
6
+ name: z.string(),
7
+ age: z.number(),
8
+ };
9
+ const zodSchema = z.object(schema);
10
+ // Type-level assertion (checked by tsc --noEmit)
11
+ expectTypeOf().toEqualTypeOf();
12
+ // Runtime check with zod validation
13
+ const valid = { name: 'John', age: 30 };
14
+ const parsed = zodSchema.parse(valid);
15
+ expect(parsed.name).toBe('John');
16
+ expect(parsed.age).toBe(30);
17
+ });
18
+ it('should make optional zod properties optional in the inferred type', () => {
19
+ const schema = {
20
+ name: z.string(),
21
+ nickname: z.string().optional(),
22
+ };
23
+ const zodSchema = z.object(schema);
24
+ // Type-level assertion (checked by tsc --noEmit)
25
+ // nickname should be optional (string | undefined with optional key)
26
+ expectTypeOf().toEqualTypeOf();
27
+ // Runtime checks - should compile without providing nickname
28
+ const withoutNickname = { name: 'John' };
29
+ const parsedWithout = zodSchema.parse(withoutNickname);
30
+ expect(parsedWithout.name).toBe('John');
31
+ expect(parsedWithout.nickname).toBeUndefined();
32
+ // Should also compile with nickname provided
33
+ const withNickname = { name: 'John', nickname: 'Johnny' };
34
+ const parsedWith = zodSchema.parse(withNickname);
35
+ expect(parsedWith.nickname).toBe('Johnny');
36
+ });
37
+ it('should handle nullable properties', () => {
38
+ const schema = {
39
+ name: z.string(),
40
+ middleName: z.string().nullable(),
41
+ };
42
+ const zodSchema = z.object(schema);
43
+ // Type-level assertion (checked by tsc --noEmit)
44
+ // Nullable properties should still be required, but allow null
45
+ expectTypeOf().toEqualTypeOf();
46
+ // Runtime checks with zod validation
47
+ const withNull = { name: 'John', middleName: null };
48
+ const parsedNull = zodSchema.parse(withNull);
49
+ expect(parsedNull.middleName).toBeNull();
50
+ const withValue = { name: 'John', middleName: 'William' };
51
+ const parsedValue = zodSchema.parse(withValue);
52
+ expect(parsedValue.middleName).toBe('William');
53
+ });
54
+ it('should handle optional and nullable combined', () => {
55
+ const schema = {
56
+ name: z.string(),
57
+ suffix: z.string().nullable().optional(),
58
+ };
59
+ const zodSchema = z.object(schema);
60
+ // Type-level assertion (checked by tsc --noEmit)
61
+ // Should be optional and nullable
62
+ expectTypeOf().toEqualTypeOf();
63
+ // Runtime checks with zod validation
64
+ const withoutSuffix = { name: 'John' };
65
+ const parsedWithout = zodSchema.parse(withoutSuffix);
66
+ expect(parsedWithout.suffix).toBeUndefined();
67
+ const withNull = { name: 'John', suffix: null };
68
+ const parsedNull = zodSchema.parse(withNull);
69
+ expect(parsedNull.suffix).toBeNull();
70
+ const withValue = { name: 'John', suffix: 'Jr.' };
71
+ const parsedValue = zodSchema.parse(withValue);
72
+ expect(parsedValue.suffix).toBe('Jr.');
73
+ });
74
+ it('should handle complex nested schemas', () => {
75
+ const schema = {
76
+ user: z.object({
77
+ name: z.string(),
78
+ email: z.string().optional(),
79
+ }),
80
+ metadata: z
81
+ .object({
82
+ createdAt: z.date(),
83
+ })
84
+ .optional(),
85
+ };
86
+ const zodSchema = z.object(schema);
87
+ // Type-level assertion (checked by tsc --noEmit)
88
+ // metadata should be optional
89
+ expectTypeOf().toEqualTypeOf();
90
+ // Runtime checks with zod validation
91
+ const withoutMetadata = {
92
+ user: { name: 'John' },
93
+ };
94
+ const parsedWithout = zodSchema.parse(withoutMetadata);
95
+ expect(parsedWithout.user.name).toBe('John');
96
+ expect(parsedWithout.metadata).toBeUndefined();
97
+ const now = new Date();
98
+ const withMetadata = {
99
+ user: { name: 'John', email: 'john@example.com' },
100
+ metadata: { createdAt: now },
101
+ };
102
+ const parsedWith = zodSchema.parse(withMetadata);
103
+ expect(parsedWith.metadata?.createdAt).toEqual(now);
104
+ });
105
+ it('should handle arrays with optional elements', () => {
106
+ const schema = {
107
+ items: z.array(z.string()),
108
+ tags: z.array(z.string()).optional(),
109
+ };
110
+ const zodSchema = z.object(schema);
111
+ // Type-level assertion (checked by tsc --noEmit)
112
+ // tags should be optional
113
+ expectTypeOf().toEqualTypeOf();
114
+ // Runtime checks with zod validation
115
+ const withoutTags = { items: ['a', 'b'] };
116
+ const parsedWithout = zodSchema.parse(withoutTags);
117
+ expect(parsedWithout.items).toEqual(['a', 'b']);
118
+ expect(parsedWithout.tags).toBeUndefined();
119
+ const withTags = { items: ['a'], tags: ['tag1', 'tag2'] };
120
+ const parsedWith = zodSchema.parse(withTags);
121
+ expect(parsedWith.tags).toEqual(['tag1', 'tag2']);
122
+ });
123
+ it('should correctly type a mixed schema', () => {
124
+ const schema = {
125
+ id: z.string(),
126
+ description: z.string().optional(),
127
+ count: z.number(),
128
+ deletedAt: z.date().nullable().optional(),
129
+ };
130
+ const zodSchema = z.object(schema);
131
+ // Type-level assertion (checked by tsc --noEmit)
132
+ expectTypeOf().toEqualTypeOf();
133
+ // Runtime checks - minimal valid object (only required fields)
134
+ const minimal = {
135
+ id: '123',
136
+ count: 0,
137
+ };
138
+ const parsedMinimal = zodSchema.parse(minimal);
139
+ expect(parsedMinimal.id).toBe('123');
140
+ expect(parsedMinimal.count).toBe(0);
141
+ // Full object
142
+ const now = new Date();
143
+ const full = {
144
+ id: '456',
145
+ description: 'A test',
146
+ count: 5,
147
+ deletedAt: now,
148
+ };
149
+ const parsedFull = zodSchema.parse(full);
150
+ expect(parsedFull.description).toBe('A test');
151
+ expect(parsedFull.deletedAt).toEqual(now);
152
+ });
153
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tigerdata/mcp-boilerplate",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "MCP boilerplate code for Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "author": "TigerData",
@@ -39,9 +39,9 @@
39
39
  "prettier:check": "prettier --check ."
40
40
  },
41
41
  "dependencies": {
42
- "@modelcontextprotocol/sdk": "^1.22.0",
42
+ "@modelcontextprotocol/sdk": "^1.23.0",
43
43
  "@opentelemetry/api": "^1.9.0",
44
- "@opentelemetry/auto-instrumentations-node": "^0.67.0",
44
+ "@opentelemetry/auto-instrumentations-node": "^0.67.1",
45
45
  "@opentelemetry/exporter-trace-otlp-grpc": "^0.208.0",
46
46
  "@opentelemetry/instrumentation-http": "^0.208.0",
47
47
  "@opentelemetry/sdk-metrics": "^2.2.0",
@@ -49,18 +49,19 @@
49
49
  "@opentelemetry/sdk-trace-node": "^2.2.0",
50
50
  "@opentelemetry/semantic-conventions": "^1.38.0",
51
51
  "express": "^5.1.0",
52
- "raw-body": "^3.0.1",
52
+ "raw-body": "^3.0.2",
53
53
  "zod": "^3.23.8"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@eslint/js": "^9.39.1",
57
+ "@types/bun": "^1.3.3",
57
58
  "@types/express": "^5.0.5",
58
59
  "@types/node": "^22.19.1",
59
- "ai": "^5.0.93",
60
+ "ai": "^5.0.102",
60
61
  "eslint": "^9.39.1",
61
62
  "prettier": "^3.6.2",
62
63
  "typescript": "^5.9.3",
63
- "typescript-eslint": "^8.46.4"
64
+ "typescript-eslint": "^8.48.0"
64
65
  },
65
66
  "publishConfig": {
66
67
  "access": "public"