Skip to content

Commit f51849a

Browse files
fix(core): preserve default values for tool parameters (#268)
* fix(core): preserve default values for tool parameters Preserve JSON Schema default across protocol and MCP transport Apply defaults in Zod param schema Update E2E Optional Params assertions to handle ZodDefault wrapper * fix(test): unroll ZodDefault wrapper in e2e * fix(test): resolve lint errors in E2E tests and MCP protocol files - Apply gts formatting to test.e2e.ts and MCP protocol files - Replace 'any' types with proper AxiosError handling in test.e2e.ts - Remove unused variables and imports - Fix Node.js globals in mock-mcp-server.js using global comments * fix(test): add missing license header to mock-mcp-server.js * fix(test): revert local testing changes (port 5001→5000, .js imports) * fix(test): scope PR to #211 and keep ZodDefault-safe e2e assertions * test(core): add coverage for parameter defaults in protocol schema * refactor(core): remove never cast for parameter defaults --------- Co-authored-by: Twisha Bansal <58483338+twishabansal@users.noreply.github.com>
1 parent 45e5eab commit f51849a

File tree

4 files changed

+61
-12
lines changed

4 files changed

+61
-12
lines changed

packages/toolbox-core/src/toolbox_core/mcp/transportBase.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ interface JsonSchema {
2929
additionalProperties?: boolean | JsonSchema;
3030
description?: string;
3131
required?: string[];
32+
default?: unknown;
3233
}
3334

3435
interface ToolDefinition {
@@ -127,6 +128,7 @@ export abstract class McpHttpTransportBase implements ITransport {
127128
description: schema.description || '',
128129
required: required.has(name),
129130
authSources,
131+
default: schema.default,
130132
...typeSchema,
131133
} as ParameterSchema);
132134
}

packages/toolbox-core/src/toolbox_core/protocol.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ interface BaseParameter {
7171
description: string;
7272
authSources?: string[];
7373
required?: boolean;
74+
default?: unknown;
7475
}
7576

7677
export type ParameterSchema = BaseParameter & TypeSchema;
@@ -106,6 +107,7 @@ const ZodBaseParameter = z.object({
106107
description: z.string(),
107108
authSources: z.array(z.string()).optional(),
108109
required: z.boolean().optional(),
110+
default: z.any().optional(),
109111
});
110112

111113
export const ZodParameterSchema: z.ZodType<ParameterSchema> =
@@ -160,11 +162,14 @@ function buildZodShapeFromTypeSchema(typeSchema: TypeSchema): ZodTypeAny {
160162
}
161163

162164
function buildZodShapeFromParam(param: ParameterSchema): ZodTypeAny {
163-
const schema = buildZodShapeFromTypeSchema(param);
165+
let schema = buildZodShapeFromTypeSchema(param);
164166
if (param.required === false) {
165-
return schema.nullish();
167+
schema = schema.nullish();
166168
}
167-
return schema;
169+
if (param.default !== undefined) {
170+
schema = schema.default(param.default);
171+
}
172+
return schema as ZodTypeAny;
168173
}
169174

170175
export function createZodSchemaFromParams(

packages/toolbox-core/test/e2e/test.e2e.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {getSupportedMcpVersions} from '../../src/toolbox_core/protocol.js';
1919
import {AxiosError} from 'axios';
2020
import {CustomGlobal} from './types.js';
2121
import {authTokenGetter} from './utils.js';
22-
import {ZodOptional, ZodNullable, ZodTypeAny} from 'zod';
22+
import {ZodTypeAny} from 'zod';
2323

2424
describe.each(getSupportedMcpVersions())(
2525
'ToolboxClient E2E MCP Tests (%s)',
@@ -359,18 +359,32 @@ describe.each(getSupportedMcpVersions())(
359359
// Optional param 'data'
360360
expect(shape.data.isOptional()).toBe(true);
361361
expect(shape.data.isNullable()).toBe(true);
362-
expect(
363-
(shape.data as ZodOptional<ZodNullable<ZodTypeAny>>).unwrap().unwrap()
364-
._def.typeName,
365-
).toBe('ZodString');
362+
{
363+
let inner: ZodTypeAny = shape.data as unknown as ZodTypeAny;
364+
while (
365+
inner?._def?.typeName === 'ZodOptional' ||
366+
inner?._def?.typeName === 'ZodNullable' ||
367+
inner?._def?.typeName === 'ZodDefault'
368+
) {
369+
inner = inner._def.innerType;
370+
}
371+
expect(inner._def.typeName).toBe('ZodString');
372+
}
366373

367374
// Optional param 'id'
368375
expect(shape.id.isOptional()).toBe(true);
369376
expect(shape.id.isNullable()).toBe(true);
370-
expect(
371-
(shape.id as ZodOptional<ZodNullable<ZodTypeAny>>).unwrap().unwrap()
372-
._def.typeName,
373-
).toBe('ZodNumber');
377+
{
378+
let inner: ZodTypeAny = shape.id as unknown as ZodTypeAny;
379+
while (
380+
inner?._def?.typeName === 'ZodOptional' ||
381+
inner?._def?.typeName === 'ZodNullable' ||
382+
inner?._def?.typeName === 'ZodDefault'
383+
) {
384+
inner = inner._def.innerType;
385+
}
386+
expect(inner._def.typeName).toBe('ZodNumber');
387+
}
374388
});
375389

376390
it('should run tool with optional params omitted', async () => {

packages/toolbox-core/test/test.protocol.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,34 @@ describe('createZodObjectSchemaFromParameters', () => {
531531
);
532532
});
533533

534+
describe('default parameters', () => {
535+
it('should preserve a default value in parameter schema validation', () => {
536+
expectParseSuccess(ZodParameterSchema, {
537+
name: 'limit',
538+
description: 'query limit',
539+
type: 'integer',
540+
required: false,
541+
default: 10,
542+
});
543+
});
544+
545+
it('should apply default value when parameter is omitted', () => {
546+
const params: ParameterSchema[] = [
547+
{
548+
name: 'limit',
549+
description: 'query limit',
550+
type: 'integer',
551+
required: false,
552+
default: 10,
553+
},
554+
];
555+
const schema = createZodSchemaFromParams(params);
556+
557+
const result = schema.parse({});
558+
expect(result).toEqual({limit: 10});
559+
});
560+
});
561+
534562
describe('optional parameters', () => {
535563
const params: ParameterSchema[] = [
536564
{name: 'requiredParam', description: 'required', type: 'string' as const},

0 commit comments

Comments
 (0)