feat!: drop Zod v3 support (#1460)
This commit is contained in:
parent
bc883afe3c
commit
be5670f4fa
51 changed files with 669 additions and 947 deletions
|
|
@ -88,12 +88,11 @@ Located in `packages/*/src/experimental/`:
|
|||
|
||||
- **Tasks**: Long-running task support with polling/resumption (`packages/core/src/experimental/tasks/`)
|
||||
|
||||
### Zod Compatibility
|
||||
### Zod Schemas
|
||||
|
||||
The SDK uses `zod/v4` internally but supports both v3 and v4 APIs. Compatibility utilities:
|
||||
The SDK uses `zod/v4` internally. Schema utilities live in:
|
||||
|
||||
- `packages/core/src/util/zod-compat.ts` - Schema parsing helpers that work across versions
|
||||
- `packages/core/src/util/zod-json-schema-compat.ts` - Converts Zod schemas to JSON Schema
|
||||
- `packages/core/src/util/schema.ts` - AnySchema alias and helpers for inspecting Zod objects
|
||||
|
||||
### Validation
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ This monorepo publishes split packages:
|
|||
- **`@modelcontextprotocol/server`**: build MCP servers
|
||||
- **`@modelcontextprotocol/client`**: build MCP clients
|
||||
|
||||
Both packages have a **required peer dependency** on `zod` for schema validation. The SDK internally imports from `zod/v4`, but remains compatible with projects using Zod v3.25+.
|
||||
Both packages have a **required peer dependency** on `zod` for schema validation. The SDK uses Zod v4.
|
||||
|
||||
### Middleware packages (optional)
|
||||
|
||||
|
|
|
|||
|
|
@ -209,10 +209,12 @@ if (error instanceof OAuthError && error.code === OAuthErrorCode.InvalidClient)
|
|||
|
||||
The variadic `.tool()`, `.prompt()`, `.resource()` methods are removed. Use the `register*` methods with a config object.
|
||||
|
||||
**IMPORTANT**: v2 requires full Zod schemas — raw shapes like `{ name: z.string() }` are no longer supported. You must wrap with `z.object()`. This applies to `inputSchema`, `outputSchema`, and `argsSchema`.
|
||||
|
||||
### Tools
|
||||
|
||||
```typescript
|
||||
// v1: server.tool(name, schema, callback)
|
||||
// v1: server.tool(name, schema, callback) - raw shape worked
|
||||
server.tool('greet', { name: z.string() }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
|
@ -227,7 +229,7 @@ server.registerTool(
|
|||
'greet',
|
||||
{
|
||||
description: 'Greet a user',
|
||||
inputSchema: { name: z.string() }
|
||||
inputSchema: z.object({ name: z.string() })
|
||||
},
|
||||
async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
|
|
@ -240,7 +242,7 @@ Config object fields: `title?`, `description?`, `inputSchema?`, `outputSchema?`,
|
|||
### Prompts
|
||||
|
||||
```typescript
|
||||
// v1: server.prompt(name, schema, callback)
|
||||
// v1: server.prompt(name, schema, callback) - raw shape worked
|
||||
server.prompt('summarize', { text: z.string() }, async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
||||
});
|
||||
|
|
@ -249,7 +251,7 @@ server.prompt('summarize', { text: z.string() }, async ({ text }) => {
|
|||
server.registerPrompt(
|
||||
'summarize',
|
||||
{
|
||||
argsSchema: { text: z.string() }
|
||||
argsSchema: z.object({ text: z.string() })
|
||||
},
|
||||
async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
||||
|
|
@ -275,6 +277,15 @@ server.registerResource('config', 'config://app', {}, async uri => {
|
|||
|
||||
Note: the third argument (`metadata`) is required — pass `{}` if no metadata.
|
||||
|
||||
### Schema Migration Quick Reference
|
||||
|
||||
| v1 (raw shape) | v2 (Zod schema) |
|
||||
|----------------|-----------------|
|
||||
| `{ name: z.string() }` | `z.object({ name: z.string() })` |
|
||||
| `{ count: z.number().optional() }` | `z.object({ count: z.number().optional() })` |
|
||||
| `{}` (empty) | `z.object({})` |
|
||||
| `undefined` (no schema) | `undefined` or omit the field |
|
||||
|
||||
## 7. Headers API
|
||||
|
||||
Transport constructors and `RequestInfo.headers` now use the Web Standard `Headers` object instead of plain objects.
|
||||
|
|
@ -385,9 +396,10 @@ Access validators via `_shims` export: `import { DefaultJsonSchemaValidator } fr
|
|||
2. Replace all imports from `@modelcontextprotocol/sdk/...` using the import mapping tables (sections 3-4), including `StreamableHTTPServerTransport` → `NodeStreamableHTTPServerTransport`
|
||||
3. Replace removed type aliases (`JSONRPCError` → `JSONRPCErrorResponse`, etc.) per section 5
|
||||
4. Replace `.tool()` / `.prompt()` / `.resource()` calls with `registerTool` / `registerPrompt` / `registerResource` per section 6
|
||||
5. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7
|
||||
6. If using `hostHeaderValidation` from server, update import and signature per section 8
|
||||
7. If using server SSE transport, migrate to Streamable HTTP
|
||||
8. If using server auth from the SDK, migrate to an external auth library
|
||||
9. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
|
||||
10. Verify: build with `tsc` / run tests
|
||||
5. **Wrap all raw Zod shapes with `z.object()`**: Change `inputSchema: { name: z.string() }` → `inputSchema: z.object({ name: z.string() })`. Same for `outputSchema` in tools and `argsSchema` in prompts.
|
||||
6. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7
|
||||
7. If using `hostHeaderValidation` from server, update import and signature per section 8
|
||||
8. If using server SSE transport, migrate to Streamable HTTP
|
||||
9. If using server auth from the SDK, migrate to an external auth library
|
||||
10. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
|
||||
11. Verify: build with `tsc` / run tests
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ server.resource('config', 'config://app', async uri => {
|
|||
|
||||
```typescript
|
||||
import { McpServer } from '@modelcontextprotocol/server';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
const server = new McpServer({ name: 'demo', version: '1.0.0' });
|
||||
|
||||
|
|
@ -219,6 +220,42 @@ server.registerResource('config', 'config://app', {}, async uri => {
|
|||
});
|
||||
```
|
||||
|
||||
### Zod schemas required (raw shapes no longer supported)
|
||||
|
||||
v2 requires full Zod schemas for `inputSchema` and `argsSchema`. Raw object shapes are no longer accepted.
|
||||
|
||||
**Before (v1):**
|
||||
|
||||
```typescript
|
||||
// Raw shape (object with Zod fields) - worked in v1
|
||||
server.tool('greet', { name: z.string() }, async ({ name }) => { ... });
|
||||
|
||||
server.registerTool('greet', {
|
||||
inputSchema: { name: z.string() } // raw shape
|
||||
}, callback);
|
||||
```
|
||||
|
||||
**After (v2):**
|
||||
|
||||
```typescript
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
// Must wrap with z.object()
|
||||
server.registerTool('greet', {
|
||||
inputSchema: z.object({ name: z.string() }) // full Zod schema
|
||||
}, async ({ name }) => { ... });
|
||||
|
||||
// For tools with no parameters, use z.object({})
|
||||
server.registerTool('ping', {
|
||||
inputSchema: z.object({})
|
||||
}, async () => { ... });
|
||||
```
|
||||
|
||||
This applies to:
|
||||
- `inputSchema` in `registerTool()`
|
||||
- `outputSchema` in `registerTool()`
|
||||
- `argsSchema` in `registerPrompt()`
|
||||
|
||||
### Host header validation moved
|
||||
|
||||
Express-specific middleware (`hostHeaderValidation()`, `localhostHostValidation()`) moved from the server package to `@modelcontextprotocol/express`. The server package now exports framework-agnostic functions instead: `validateHostHeader()`, `localhostAllowedHostnames()`,
|
||||
|
|
|
|||
|
|
@ -368,7 +368,6 @@ class InteractiveOAuthClient {
|
|||
name: toolName,
|
||||
arguments: toolArgs
|
||||
},
|
||||
CallToolResultSchema,
|
||||
{
|
||||
task: {
|
||||
taskId: `task-${Date.now()}`,
|
||||
|
|
|
|||
|
|
@ -882,7 +882,6 @@ async function callToolTask(name: string, args: Record<string, unknown>): Promis
|
|||
name,
|
||||
arguments: args
|
||||
},
|
||||
CallToolResultSchema,
|
||||
{
|
||||
task: {
|
||||
ttl: 60_000 // Keep results for 60 seconds
|
||||
|
|
|
|||
|
|
@ -10,13 +10,7 @@
|
|||
import { createInterface } from 'node:readline';
|
||||
|
||||
import type { CreateMessageRequest, CreateMessageResult, TextContent } from '@modelcontextprotocol/client';
|
||||
import {
|
||||
CallToolResultSchema,
|
||||
Client,
|
||||
ProtocolError,
|
||||
ProtocolErrorCode,
|
||||
StreamableHTTPClientTransport
|
||||
} from '@modelcontextprotocol/client';
|
||||
import { Client, ProtocolError, ProtocolErrorCode, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
|
||||
|
||||
// Create readline interface for user input
|
||||
const readline = createInterface({
|
||||
|
|
@ -127,7 +121,6 @@ async function run(url: string): Promise<void> {
|
|||
|
||||
const confirmStream = client.experimental.tasks.callToolStream(
|
||||
{ name: 'confirm_delete', arguments: { filename: 'important.txt' } },
|
||||
CallToolResultSchema,
|
||||
{ task: { ttl: 60_000 } }
|
||||
);
|
||||
|
||||
|
|
@ -158,10 +151,7 @@ async function run(url: string): Promise<void> {
|
|||
|
||||
const haikuStream = client.experimental.tasks.callToolStream(
|
||||
{ name: 'write_haiku', arguments: { topic: 'autumn leaves' } },
|
||||
CallToolResultSchema,
|
||||
{
|
||||
task: { ttl: 60_000 }
|
||||
}
|
||||
{ task: { ttl: 60_000 } }
|
||||
);
|
||||
|
||||
for await (const message of haikuStream) {
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ server.registerTool(
|
|||
'get-protocol-info',
|
||||
{
|
||||
title: 'Protocol Info',
|
||||
description: 'Returns protocol version configuration',
|
||||
inputSchema: {}
|
||||
description: 'Returns protocol version configuration'
|
||||
},
|
||||
async (): Promise<CallToolResult> => ({
|
||||
content: [
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ const mcpServer = new McpServer(
|
|||
mcpServer.registerTool(
|
||||
'register_user',
|
||||
{
|
||||
description: 'Register a new user account by collecting their information',
|
||||
inputSchema: {}
|
||||
description: 'Register a new user account by collecting their information'
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
|
|
@ -132,8 +131,7 @@ mcpServer.registerTool(
|
|||
mcpServer.registerTool(
|
||||
'create_event',
|
||||
{
|
||||
description: 'Create a calendar event by collecting event details',
|
||||
inputSchema: {}
|
||||
description: 'Create a calendar event by collecting event details'
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
|
|
@ -237,8 +235,7 @@ mcpServer.registerTool(
|
|||
mcpServer.registerTool(
|
||||
'update_shipping_address',
|
||||
{
|
||||
description: 'Update shipping address with validation',
|
||||
inputSchema: {}
|
||||
description: 'Update shipping address with validation'
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import { isInitializeRequest, McpServer, UrlElicitationRequiredError } from '@mo
|
|||
import cors from 'cors';
|
||||
import type { Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
import { z } from 'zod';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
import { InMemoryEventStore } from './inMemoryEventStore.js';
|
||||
|
||||
|
|
@ -42,9 +42,9 @@ const getServer = () => {
|
|||
'payment-confirm',
|
||||
{
|
||||
description: 'A tool that confirms a payment directly with a user',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
cartId: z.string().describe('The ID of the cart to confirm')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ cartId }, extra): Promise<CallToolResult> => {
|
||||
/*
|
||||
|
|
@ -75,9 +75,9 @@ const getServer = () => {
|
|||
'third-party-auth',
|
||||
{
|
||||
description: 'A demo tool that requires third-party OAuth credentials',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
param1: z.string().describe('First parameter')
|
||||
}
|
||||
})
|
||||
},
|
||||
async (_, extra): Promise<CallToolResult> => {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ server.registerTool(
|
|||
{
|
||||
title: 'Greeting Tool',
|
||||
description: 'A simple greeting tool',
|
||||
inputSchema: { name: z.string().describe('Name to greet') }
|
||||
inputSchema: z.object({ name: z.string().describe('Name to greet') })
|
||||
},
|
||||
async ({ name }): Promise<CallToolResult> => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ const getServer = () => {
|
|||
'greet',
|
||||
{
|
||||
description: 'A simple greeting tool',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string().describe('Name to greet')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }): Promise<CallToolResult> => {
|
||||
return {
|
||||
|
|
@ -47,9 +47,9 @@ const getServer = () => {
|
|||
'multi-greet',
|
||||
{
|
||||
description: 'A tool that sends different greetings with delays between them',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string().describe('Name to greet')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }, extra): Promise<CallToolResult> => {
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ server.registerTool(
|
|||
'get_weather',
|
||||
{
|
||||
description: 'Get weather information for a city',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
city: z.string().describe('City name'),
|
||||
country: z.string().describe('Country code (e.g., US, UK)')
|
||||
},
|
||||
outputSchema: {
|
||||
}),
|
||||
outputSchema: z.object({
|
||||
temperature: z.object({
|
||||
celsius: z.number(),
|
||||
fahrenheit: z.number()
|
||||
|
|
@ -32,7 +32,7 @@ server.registerTool(
|
|||
speed_kmh: z.number(),
|
||||
direction: z.string()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ city, country }) => {
|
||||
// Parameters are available but not used in this example
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ const getServer = () => {
|
|||
'greeting-template',
|
||||
{
|
||||
description: 'A simple greeting prompt template',
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string().describe('Name to include in greeting')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }): Promise<GetPromptResult> => {
|
||||
return {
|
||||
|
|
@ -44,10 +44,10 @@ const getServer = () => {
|
|||
'start-notification-stream',
|
||||
{
|
||||
description: 'Starts sending periodic notifications for testing resumability',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
|
||||
count: z.number().describe('Number of notifications to send (0 for 100)').default(10)
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ interval, count }, extra): Promise<CallToolResult> => {
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ const getServer = () => {
|
|||
{
|
||||
title: 'Greeting Tool', // Display name for UI
|
||||
description: 'A simple greeting tool',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string().describe('Name to greet')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }): Promise<CallToolResult> => {
|
||||
return {
|
||||
|
|
@ -79,9 +79,9 @@ const getServer = () => {
|
|||
'multi-greet',
|
||||
{
|
||||
description: 'A tool that sends different greetings with delays between them',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string().describe('Name to greet')
|
||||
},
|
||||
}),
|
||||
annotations: {
|
||||
title: 'Multiple Greeting Tool',
|
||||
readOnlyHint: true,
|
||||
|
|
@ -135,9 +135,9 @@ const getServer = () => {
|
|||
'collect-user-info',
|
||||
{
|
||||
description: 'A tool that collects user information through form elicitation',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
infoType: z.enum(['contact', 'preferences', 'feedback']).describe('Type of information to collect')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ infoType }, extra): Promise<CallToolResult> => {
|
||||
let message: string;
|
||||
|
|
@ -298,9 +298,9 @@ const getServer = () => {
|
|||
{
|
||||
title: 'Greeting Template', // Display name for UI
|
||||
description: 'A simple greeting prompt template',
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string().describe('Name to include in greeting')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }): Promise<GetPromptResult> => {
|
||||
return {
|
||||
|
|
@ -322,10 +322,10 @@ const getServer = () => {
|
|||
'start-notification-stream',
|
||||
{
|
||||
description: 'Starts sending periodic notifications for testing resumability',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
interval: z.number().describe('Interval in milliseconds between notifications').default(100),
|
||||
count: z.number().describe('Number of notifications to send (0 for 100)').default(50)
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ interval, count }, extra): Promise<CallToolResult> => {
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
|
@ -427,9 +427,9 @@ const getServer = () => {
|
|||
{
|
||||
title: 'List Files with ResourceLinks',
|
||||
description: 'Returns a list of files as ResourceLinks without embedding their content',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
includeDescriptions: z.boolean().optional().describe('Whether to include descriptions in the resource links')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ includeDescriptions = true }): Promise<CallToolResult> => {
|
||||
const resourceLinks: ResourceLink[] = [
|
||||
|
|
@ -479,9 +479,9 @@ const getServer = () => {
|
|||
{
|
||||
title: 'Delay',
|
||||
description: 'A simple tool that delays for a specified duration, useful for testing task execution',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
duration: z.number().describe('Duration in milliseconds').default(5000)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ duration }, { taskStore, taskRequestedTtl }) {
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ mcpServer.registerTool(
|
|||
'summarize',
|
||||
{
|
||||
description: 'Summarize any text using an LLM',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
text: z.string().describe('Text to summarize')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ text }) => {
|
||||
// Call the LLM through MCP sampling
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ import {
|
|||
ListResourceTemplatesResultSchema,
|
||||
ListToolsResultSchema,
|
||||
mergeCapabilities,
|
||||
parseSchema,
|
||||
Protocol,
|
||||
ProtocolError,
|
||||
ProtocolErrorCode,
|
||||
ReadResourceResultSchema,
|
||||
safeParse,
|
||||
SdkError,
|
||||
SdkErrorCode
|
||||
} from '@modelcontextprotocol/core';
|
||||
|
|
@ -320,7 +320,7 @@ export class Client<
|
|||
request: RequestTypeMap[M],
|
||||
extra: RequestHandlerExtra<ClientRequest | RequestT, ClientNotification | NotificationT>
|
||||
): Promise<ClientResult | ResultT> => {
|
||||
const validatedRequest = safeParse(ElicitRequestSchema, request);
|
||||
const validatedRequest = parseSchema(ElicitRequestSchema, request);
|
||||
if (!validatedRequest.success) {
|
||||
// Type guard: if success is false, error is guaranteed to exist
|
||||
const errorMessage =
|
||||
|
|
@ -344,7 +344,7 @@ export class Client<
|
|||
|
||||
// When task creation is requested, validate and return CreateTaskResult
|
||||
if (params.task) {
|
||||
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
||||
const taskValidationResult = parseSchema(CreateTaskResultSchema, result);
|
||||
if (!taskValidationResult.success) {
|
||||
const errorMessage =
|
||||
taskValidationResult.error instanceof Error
|
||||
|
|
@ -356,7 +356,7 @@ export class Client<
|
|||
}
|
||||
|
||||
// For non-task requests, validate against ElicitResultSchema
|
||||
const validationResult = safeParse(ElicitResultSchema, result);
|
||||
const validationResult = parseSchema(ElicitResultSchema, result);
|
||||
if (!validationResult.success) {
|
||||
// Type guard: if success is false, error is guaranteed to exist
|
||||
const errorMessage =
|
||||
|
|
@ -393,7 +393,7 @@ export class Client<
|
|||
request: RequestTypeMap[M],
|
||||
extra: RequestHandlerExtra<ClientRequest | RequestT, ClientNotification | NotificationT>
|
||||
): Promise<ClientResult | ResultT> => {
|
||||
const validatedRequest = safeParse(CreateMessageRequestSchema, request);
|
||||
const validatedRequest = parseSchema(CreateMessageRequestSchema, request);
|
||||
if (!validatedRequest.success) {
|
||||
const errorMessage =
|
||||
validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
||||
|
|
@ -406,7 +406,7 @@ export class Client<
|
|||
|
||||
// When task creation is requested, validate and return CreateTaskResult
|
||||
if (params.task) {
|
||||
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
||||
const taskValidationResult = parseSchema(CreateTaskResultSchema, result);
|
||||
if (!taskValidationResult.success) {
|
||||
const errorMessage =
|
||||
taskValidationResult.error instanceof Error
|
||||
|
|
@ -420,7 +420,7 @@ export class Client<
|
|||
// For non-task requests, validate against appropriate schema based on tools presence
|
||||
const hasTools = params.tools || params.toolChoice;
|
||||
const resultSchema = hasTools ? CreateMessageResultWithToolsSchema : CreateMessageResultSchema;
|
||||
const validationResult = safeParse(resultSchema, result);
|
||||
const validationResult = parseSchema(resultSchema, result);
|
||||
if (!validationResult.success) {
|
||||
const errorMessage =
|
||||
validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
||||
|
|
@ -873,7 +873,7 @@ export class Client<
|
|||
fetcher: () => Promise<T[]>
|
||||
): void {
|
||||
// Validate options using Zod schema (validates autoRefresh and debounceMs)
|
||||
const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
|
||||
const parseResult = parseSchema(ListChangedOptionsBaseSchema, options);
|
||||
if (!parseResult.success) {
|
||||
throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import type {
|
|||
CallToolRequest,
|
||||
CancelTaskResult,
|
||||
ClientRequest,
|
||||
CompatibilityCallToolResultSchema,
|
||||
GetTaskResult,
|
||||
ListTasksResult,
|
||||
Notification,
|
||||
|
|
@ -92,11 +91,10 @@ export class ExperimentalClientTasks<
|
|||
*
|
||||
* @experimental
|
||||
*/
|
||||
async *callToolStream<T extends typeof CallToolResultSchema | typeof CompatibilityCallToolResultSchema>(
|
||||
async *callToolStream(
|
||||
params: CallToolRequest['params'],
|
||||
resultSchema: T = CallToolResultSchema as T,
|
||||
options?: RequestOptions
|
||||
): AsyncGenerator<ResponseMessage<SchemaOutput<T>>, void, void> {
|
||||
): AsyncGenerator<ResponseMessage<SchemaOutput<typeof CallToolResultSchema>>, void, void> {
|
||||
// Access Client's internal methods
|
||||
const clientInternal = this._client as unknown as ClientInternal<RequestT>;
|
||||
|
||||
|
|
@ -108,7 +106,7 @@ export class ExperimentalClientTasks<
|
|||
task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : undefined)
|
||||
};
|
||||
|
||||
const stream = clientInternal.requestStream({ method: 'tools/call', params }, resultSchema, optionsWithTask);
|
||||
const stream = clientInternal.requestStream({ method: 'tools/call', params }, CallToolResultSchema, optionsWithTask);
|
||||
|
||||
// Get the validator for this tool (if it has an output schema)
|
||||
const validator = clientInternal.getToolOutputValidator(params.name);
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@
|
|||
"ajv": "catalog:runtimeShared",
|
||||
"ajv-formats": "catalog:runtimeShared",
|
||||
"json-schema-typed": "catalog:runtimeShared",
|
||||
"zod": "catalog:runtimeShared",
|
||||
"zod-to-json-schema": "catalog:runtimeShared"
|
||||
"zod": "catalog:runtimeShared"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cfworker/json-schema": "catalog:runtimeShared",
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ export * from './shared/transport.js';
|
|||
export * from './shared/uriTemplate.js';
|
||||
export * from './types/types.js';
|
||||
export * from './util/inMemory.js';
|
||||
export * from './util/zodCompat.js';
|
||||
export * from './util/zodJsonSchemaCompat.js';
|
||||
export * from './util/schema.js';
|
||||
|
||||
// experimental exports
|
||||
export * from './experimental/index.js';
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue