Skip to content

Commit 3e2862e

Browse files
Merge branch 'main' into feat-fetch-transport
2 parents 4dfa889 + 1d42547 commit 3e2862e

File tree

5 files changed

+93
-14
lines changed

5 files changed

+93
-14
lines changed

src/server/zod-compat.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export interface ZodV4Internal {
3535
value?: unknown;
3636
values?: unknown[];
3737
shape?: Record<string, AnySchema> | (() => Record<string, AnySchema>);
38-
description?: string;
3938
};
4039
};
4140
value?: unknown;
@@ -220,15 +219,12 @@ export function getParseErrorMessage(error: unknown): string {
220219
/**
221220
* Gets the description from a schema, if available.
222221
* Works with both Zod v3 and v4.
222+
*
223+
* Both versions expose a `.description` getter that returns the description
224+
* from their respective internal storage (v3: _def, v4: globalRegistry).
223225
*/
224226
export function getSchemaDescription(schema: AnySchema): string | undefined {
225-
if (isZ4Schema(schema)) {
226-
const v4Schema = schema as unknown as ZodV4Internal;
227-
return v4Schema._zod?.def?.description;
228-
}
229-
const v3Schema = schema as unknown as ZodV3Internal;
230-
// v3 may have description on the schema itself or in _def
231-
return (schema as { description?: string }).description ?? v3Schema._def?.description;
227+
return (schema as { description?: string }).description;
232228
}
233229

234230
/**

src/types.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,15 @@ export const IconSchema = z.object({
279279
*
280280
* If not provided, the client should assume that the icon can be used at any size.
281281
*/
282-
sizes: z.array(z.string()).optional()
282+
sizes: z.array(z.string()).optional(),
283+
/**
284+
* Optional specifier for the theme this icon is designed for. `light` indicates
285+
* the icon is designed to be used with a light background, and `dark` indicates
286+
* the icon is designed to be used with a dark background.
287+
*
288+
* If not provided, the client should assume the icon can be used with any theme.
289+
*/
290+
theme: z.enum(['light', 'dark']).optional()
283291
});
284292

285293
/**
@@ -329,7 +337,16 @@ export const ImplementationSchema = BaseMetadataSchema.extend({
329337
/**
330338
* An optional URL of the website for this implementation.
331339
*/
332-
websiteUrl: z.string().optional()
340+
websiteUrl: z.string().optional(),
341+
342+
/**
343+
* An optional human-readable description of what this implementation does.
344+
*
345+
* This can be used by clients or servers to provide context about their purpose
346+
* and capabilities. For example, a server might describe the types of resources
347+
* or tools it provides, while a client might describe its intended use case.
348+
*/
349+
description: z.string().optional()
333350
});
334351

335352
const FormElicitationCapabilitySchema = z.intersection(

src/validation/ajv-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* AJV-based JSON Schema validator provider
33
*/
44

5-
import { Ajv } from 'ajv';
5+
import Ajv from 'ajv';
66
import _addFormats from 'ajv-formats';
77
import type { JsonSchemaType, JsonSchemaValidator, JsonSchemaValidatorResult, jsonSchemaValidator } from './types.js';
88

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Regression test for https://github.com/modelcontextprotocol/typescript-sdk/issues/1277
3+
*
4+
* Zod v4 stores `.describe()` descriptions directly on the schema object,
5+
* not in `._zod.def.description`. This test verifies that descriptions are
6+
* correctly extracted for prompt arguments.
7+
*/
8+
9+
import { Client } from '../../src/client/index.js';
10+
import { InMemoryTransport } from '../../src/inMemory.js';
11+
import { ListPromptsResultSchema } from '../../src/types.js';
12+
import { McpServer } from '../../src/server/mcp.js';
13+
import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js';
14+
15+
describe.each(zodTestMatrix)('Issue #1277: $zodVersionLabel', (entry: ZodMatrixEntry) => {
16+
const { z } = entry;
17+
18+
test('should preserve argument descriptions from .describe()', async () => {
19+
const mcpServer = new McpServer({
20+
name: 'test server',
21+
version: '1.0'
22+
});
23+
const client = new Client({
24+
name: 'test client',
25+
version: '1.0'
26+
});
27+
28+
mcpServer.prompt(
29+
'test',
30+
{
31+
name: z.string().describe('The user name'),
32+
value: z.string().describe('The value to set')
33+
},
34+
async ({ name, value }) => ({
35+
messages: [
36+
{
37+
role: 'assistant',
38+
content: {
39+
type: 'text',
40+
text: `${name}: ${value}`
41+
}
42+
}
43+
]
44+
})
45+
);
46+
47+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
48+
49+
await Promise.all([client.connect(clientTransport), mcpServer.server.connect(serverTransport)]);
50+
51+
const result = await client.request(
52+
{
53+
method: 'prompts/list'
54+
},
55+
ListPromptsResultSchema
56+
);
57+
58+
expect(result.prompts).toHaveLength(1);
59+
expect(result.prompts[0].name).toBe('test');
60+
expect(result.prompts[0].arguments).toEqual([
61+
{ name: 'name', required: true, description: 'The user name' },
62+
{ name: 'value', required: true, description: 'The value to set' }
63+
]);
64+
});
65+
});

tsconfig.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
{
22
"compilerOptions": {
3-
"target": "es2018",
4-
"module": "Node16",
5-
"moduleResolution": "Node16",
3+
"target": "es2020",
4+
"module": "es2022",
5+
"moduleResolution": "bundler",
66
"declaration": true,
77
"declarationMap": true,
88
"sourceMap": true,
99
"outDir": "./dist",
1010
"strict": true,
1111
"esModuleInterop": true,
12+
"allowSyntheticDefaultImports": true,
1213
"forceConsistentCasingInFileNames": true,
1314
"resolveJsonModule": true,
1415
"isolatedModules": true,

0 commit comments

Comments
 (0)