feat!: drop Zod v3 support (#1460)
This commit is contained in:
parent
bc883afe3c
commit
be5670f4fa
9 changed files with 669 additions and 947 deletions
|
|
@ -13,7 +13,7 @@ import {
|
|||
SUPPORTED_PROTOCOL_VERSIONS
|
||||
} from '@modelcontextprotocol/core';
|
||||
import { InMemoryTaskStore, McpServer, Server } from '@modelcontextprotocol/server';
|
||||
import * as z4 from 'zod/v4';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
/***
|
||||
* Test: Initialize with Matching Protocol Version
|
||||
|
|
@ -2266,7 +2266,7 @@ describe('Task-based execution', () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
@ -2342,7 +2342,7 @@ describe('Task-based execution', () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
@ -2419,7 +2419,7 @@ describe('Task-based execution', () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
@ -2459,9 +2459,12 @@ describe('Task-based execution', () => {
|
|||
|
||||
// Create a task using callToolStream to capture the task ID
|
||||
let taskId: string | undefined;
|
||||
const stream = client.experimental.tasks.callToolStream({ name: 'test-tool', arguments: {} }, CallToolResultSchema, {
|
||||
task: { ttl: 60_000 }
|
||||
});
|
||||
const stream = client.experimental.tasks.callToolStream(
|
||||
{ name: 'test-tool', arguments: {} },
|
||||
{
|
||||
task: { ttl: 60_000 }
|
||||
}
|
||||
);
|
||||
|
||||
for await (const message of stream) {
|
||||
if (message.type === 'taskCreated') {
|
||||
|
|
@ -2500,7 +2503,7 @@ describe('Task-based execution', () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
@ -2983,9 +2986,9 @@ describe('Task-based execution', () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {
|
||||
id: z4.string()
|
||||
}
|
||||
inputSchema: z.object({
|
||||
id: z.string()
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ id }, extra) {
|
||||
|
|
@ -3253,7 +3256,7 @@ test('should respect server task capabilities', async () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,9 @@
|
|||
import { Client } from '@modelcontextprotocol/client';
|
||||
import { InMemoryTransport, ListPromptsResultSchema } from '@modelcontextprotocol/core';
|
||||
import { McpServer } from '@modelcontextprotocol/server';
|
||||
import type { ZodMatrixEntry } from '@modelcontextprotocol/test-helpers';
|
||||
import { zodTestMatrix } from '@modelcontextprotocol/test-helpers';
|
||||
|
||||
describe.each(zodTestMatrix)('Issue #1277: $zodVersionLabel', (entry: ZodMatrixEntry) => {
|
||||
const { z } = entry;
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
describe('Issue #1277: Zod v4', () => {
|
||||
test('should preserve argument descriptions from .describe()', async () => {
|
||||
const mcpServer = new McpServer({
|
||||
name: 'test server',
|
||||
|
|
@ -28,10 +25,10 @@ describe.each(zodTestMatrix)('Issue #1277: $zodVersionLabel', (entry: ZodMatrixE
|
|||
mcpServer.registerPrompt(
|
||||
'test',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string().describe('The user name'),
|
||||
value: z.string().describe('The value to set')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name, value }) => ({
|
||||
messages: [
|
||||
|
|
|
|||
|
|
@ -9,12 +9,9 @@
|
|||
import { Client } from '@modelcontextprotocol/client';
|
||||
import { CallToolResultSchema, InMemoryTransport } from '@modelcontextprotocol/core';
|
||||
import { McpServer } from '@modelcontextprotocol/server';
|
||||
import type { ZodMatrixEntry } from '@modelcontextprotocol/test-helpers';
|
||||
import { zodTestMatrix } from '@modelcontextprotocol/test-helpers';
|
||||
|
||||
describe.each(zodTestMatrix)('Issue #400: $zodVersionLabel', (entry: ZodMatrixEntry) => {
|
||||
const { z } = entry;
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
describe('Issue #400: Zod v4', () => {
|
||||
test('should accept undefined arguments when all tool params are optional', async () => {
|
||||
const mcpServer = new McpServer({
|
||||
name: 'test server',
|
||||
|
|
@ -28,10 +25,10 @@ describe.each(zodTestMatrix)('Issue #400: $zodVersionLabel', (entry: ZodMatrixEn
|
|||
mcpServer.registerTool(
|
||||
'optional-params-tool',
|
||||
{
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
limit: z.number().optional(),
|
||||
offset: z.number().optional()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ limit, offset }) => ({
|
||||
content: [
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import { createMcpExpressApp } from '@modelcontextprotocol/express';
|
|||
import { InMemoryTaskStore, McpServer, Server } from '@modelcontextprotocol/server';
|
||||
import type { Request, Response } from 'express';
|
||||
import supertest from 'supertest';
|
||||
import * as z4 from 'zod/v4';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
describe('Server with standard protocol methods', () => {
|
||||
/*
|
||||
|
|
@ -2143,7 +2143,7 @@ describe('Task-based execution', () => {
|
|||
'test-tool',
|
||||
{
|
||||
description: 'A test tool',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
@ -2200,11 +2200,14 @@ describe('Task-based execution', () => {
|
|||
|
||||
// Use callToolStream to create a task and capture the task ID
|
||||
let taskId: string | undefined;
|
||||
const stream = client.experimental.tasks.callToolStream({ name: 'test-tool', arguments: {} }, CallToolResultSchema, {
|
||||
task: {
|
||||
ttl: 60_000
|
||||
const stream = client.experimental.tasks.callToolStream(
|
||||
{ name: 'test-tool', arguments: {} },
|
||||
{
|
||||
task: {
|
||||
ttl: 60_000
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
for await (const message of stream) {
|
||||
if (message.type === 'taskCreated') {
|
||||
|
|
@ -2335,7 +2338,7 @@ describe('Task-based execution', () => {
|
|||
);
|
||||
|
||||
// Track the elicitation request to verify related-task metadata
|
||||
let capturedElicitRequest: z4.infer<typeof ElicitRequestSchema> | null = null;
|
||||
let capturedElicitRequest: z.infer<typeof ElicitRequestSchema> | null = null;
|
||||
|
||||
// Set up client elicitation handler
|
||||
client.setRequestHandler('elicitation/create', async (request, extra) => {
|
||||
|
|
@ -2365,7 +2368,7 @@ describe('Task-based execution', () => {
|
|||
'collect-info',
|
||||
{
|
||||
description: 'Collects user info via elicitation',
|
||||
inputSchema: {}
|
||||
inputSchema: z.object({})
|
||||
},
|
||||
{
|
||||
async createTask(_args, extra) {
|
||||
|
|
@ -2427,11 +2430,14 @@ describe('Task-based execution', () => {
|
|||
|
||||
// Call tool WITH task creation using callToolStream to capture task ID
|
||||
let taskId: string | undefined;
|
||||
const stream = client.experimental.tasks.callToolStream({ name: 'collect-info', arguments: {} }, CallToolResultSchema, {
|
||||
task: {
|
||||
ttl: 60_000
|
||||
const stream = client.experimental.tasks.callToolStream(
|
||||
{ name: 'collect-info', arguments: {} },
|
||||
{
|
||||
task: {
|
||||
ttl: 60_000
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
for await (const message of stream) {
|
||||
if (message.type === 'taskCreated') {
|
||||
|
|
@ -2841,10 +2847,10 @@ describe('Task-based execution', () => {
|
|||
'async-tool',
|
||||
{
|
||||
description: 'An async test tool',
|
||||
inputSchema: {
|
||||
delay: z4.number().optional().default(10),
|
||||
taskNum: z4.number().optional()
|
||||
}
|
||||
inputSchema: z.object({
|
||||
delay: z.number().optional().default(10),
|
||||
taskNum: z.number().optional()
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ delay, taskNum }, extra) {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@ import {
|
|||
UrlElicitationRequiredError
|
||||
} from '@modelcontextprotocol/core';
|
||||
import { completable, McpServer, ResourceTemplate } from '@modelcontextprotocol/server';
|
||||
import type { ZodMatrixEntry } from '@modelcontextprotocol/test-helpers';
|
||||
import { zodTestMatrix } from '@modelcontextprotocol/test-helpers';
|
||||
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
function createLatch() {
|
||||
let latch = false;
|
||||
|
|
@ -37,9 +36,7 @@ function createLatch() {
|
|||
};
|
||||
}
|
||||
|
||||
describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
||||
const { z } = entry;
|
||||
|
||||
describe('Zod v4', () => {
|
||||
describe('McpServer', () => {
|
||||
/***
|
||||
* Test: Basic Server Instance
|
||||
|
|
@ -111,9 +108,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'long-operation',
|
||||
{
|
||||
description: 'A long running operation with progress updates',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
steps: z.number().min(1).describe('Number of steps to perform')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ steps }, { sendNotification, _meta }) => {
|
||||
const progressToken = _meta?.progressToken;
|
||||
|
|
@ -406,9 +403,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
const tool = mcpServer.registerTool(
|
||||
'test',
|
||||
{
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => ({
|
||||
content: [
|
||||
|
|
@ -422,10 +419,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
|
||||
// Update the tool with a different schema
|
||||
tool.update({
|
||||
paramsSchema: {
|
||||
paramsSchema: z.object({
|
||||
name: z.string(),
|
||||
value: z.number()
|
||||
},
|
||||
}),
|
||||
callback: async ({ name, value }) => ({
|
||||
content: [
|
||||
{
|
||||
|
|
@ -502,9 +499,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
const tool = mcpServer.registerTool(
|
||||
'test',
|
||||
{
|
||||
outputSchema: {
|
||||
outputSchema: z.object({
|
||||
result: z.number()
|
||||
}
|
||||
})
|
||||
},
|
||||
async () => ({
|
||||
content: [{ type: 'text', text: '' }],
|
||||
|
|
@ -516,10 +513,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
|
||||
// Update the tool with a different outputSchema
|
||||
tool.update({
|
||||
outputSchema: {
|
||||
outputSchema: z.object({
|
||||
result: z.number(),
|
||||
sum: z.number()
|
||||
},
|
||||
}),
|
||||
callback: async () => ({
|
||||
content: [{ type: 'text', text: '' }],
|
||||
structuredContent: {
|
||||
|
|
@ -648,7 +645,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerTool(
|
||||
'test',
|
||||
{
|
||||
inputSchema: { name: z.string(), value: z.number() }
|
||||
inputSchema: z.object({ name: z.string(), value: z.number() })
|
||||
},
|
||||
async ({ name, value }) => ({
|
||||
content: [{ type: 'text', text: `${name}: ${value}` }]
|
||||
|
|
@ -796,7 +793,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerTool(
|
||||
'test',
|
||||
{
|
||||
inputSchema: { name: z.string() },
|
||||
inputSchema: z.object({ name: z.string() }),
|
||||
annotations: { title: 'Test Tool', readOnlyHint: true }
|
||||
},
|
||||
async ({ name }) => ({
|
||||
|
|
@ -839,7 +836,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test',
|
||||
{
|
||||
description: 'A tool with everything',
|
||||
inputSchema: { name: z.string() },
|
||||
inputSchema: z.object({ name: z.string() }),
|
||||
annotations: {
|
||||
title: 'Complete Test Tool',
|
||||
readOnlyHint: true,
|
||||
|
|
@ -935,10 +932,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerTool(
|
||||
'test',
|
||||
{
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string(),
|
||||
value: z.number()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name, value }) => ({
|
||||
content: [
|
||||
|
|
@ -1044,14 +1041,14 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test',
|
||||
{
|
||||
description: 'Test tool with structured output',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
},
|
||||
outputSchema: {
|
||||
}),
|
||||
outputSchema: z.object({
|
||||
processedInput: z.string(),
|
||||
resultType: z.string(),
|
||||
timestamp: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ input }) => ({
|
||||
structuredContent: {
|
||||
|
|
@ -1146,13 +1143,13 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test',
|
||||
{
|
||||
description: 'Test tool with output schema but missing structured content',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
},
|
||||
outputSchema: {
|
||||
}),
|
||||
outputSchema: z.object({
|
||||
processedInput: z.string(),
|
||||
resultType: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ input }) => ({
|
||||
// Only return content without structuredContent
|
||||
|
|
@ -1207,13 +1204,13 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test',
|
||||
{
|
||||
description: 'Test tool with output schema but missing structured content',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
},
|
||||
outputSchema: {
|
||||
}),
|
||||
outputSchema: z.object({
|
||||
processedInput: z.string(),
|
||||
resultType: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ input }) => ({
|
||||
content: [
|
||||
|
|
@ -1267,14 +1264,14 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test',
|
||||
{
|
||||
description: 'Test tool with invalid structured output',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
},
|
||||
outputSchema: {
|
||||
}),
|
||||
outputSchema: z.object({
|
||||
processedInput: z.string(),
|
||||
resultType: z.string(),
|
||||
timestamp: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ input }) => ({
|
||||
content: [
|
||||
|
|
@ -1490,9 +1487,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test',
|
||||
{
|
||||
description: 'Test tool',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ input }) => ({
|
||||
content: [
|
||||
|
|
@ -1696,7 +1693,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test-with-meta',
|
||||
{
|
||||
description: 'A tool with _meta field',
|
||||
inputSchema: { name: z.string() },
|
||||
inputSchema: z.object({ name: z.string() }),
|
||||
_meta: metaData
|
||||
},
|
||||
async ({ name }) => ({
|
||||
|
|
@ -1733,7 +1730,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'test-without-meta',
|
||||
{
|
||||
description: 'A tool without _meta field',
|
||||
inputSchema: { name: z.string() }
|
||||
inputSchema: z.object({ name: z.string() })
|
||||
},
|
||||
async ({ name }) => ({
|
||||
content: [{ type: 'text', text: `Hello, ${name}!` }]
|
||||
|
|
@ -1784,7 +1781,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'task-tool',
|
||||
{
|
||||
description: 'A tool with task support',
|
||||
inputSchema: { input: z.string() },
|
||||
inputSchema: z.object({ input: z.string() }),
|
||||
execution: {
|
||||
taskSupport: 'required'
|
||||
}
|
||||
|
|
@ -1853,7 +1850,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'optional-task-tool',
|
||||
{
|
||||
description: 'A tool with optional task support',
|
||||
inputSchema: { input: z.string() },
|
||||
inputSchema: z.object({ input: z.string() }),
|
||||
execution: {
|
||||
taskSupport: 'optional'
|
||||
}
|
||||
|
|
@ -3034,9 +3031,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
const prompt = mcpServer.registerPrompt(
|
||||
'test',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => ({
|
||||
messages: [
|
||||
|
|
@ -3053,10 +3050,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
|
||||
// Update the prompt with a different schema
|
||||
prompt.update({
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string(),
|
||||
value: z.string()
|
||||
},
|
||||
}),
|
||||
callback: async ({ name, value }) => ({
|
||||
messages: [
|
||||
{
|
||||
|
|
@ -3260,10 +3257,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string(),
|
||||
value: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name, value }) => ({
|
||||
messages: [
|
||||
|
|
@ -3355,10 +3352,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string(),
|
||||
value: z.string().min(3)
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name, value }) => ({
|
||||
messages: [
|
||||
|
|
@ -3476,7 +3473,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
});
|
||||
|
||||
// This should succeed
|
||||
mcpServer.registerPrompt('echo', { argsSchema: { message: z.string() } }, ({ message }) => ({
|
||||
mcpServer.registerPrompt('echo', { argsSchema: z.object({ message: z.string() }) }, ({ message }) => ({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
|
|
@ -3521,7 +3518,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
// Register a prompt with completion
|
||||
mcpServer.registerPrompt(
|
||||
'echo',
|
||||
{ argsSchema: { message: completable(z.string(), () => ['hello', 'world']) } },
|
||||
{ argsSchema: z.object({ message: completable(z.string(), () => ['hello', 'world']) }) },
|
||||
({ message }) => ({
|
||||
messages: [
|
||||
{
|
||||
|
|
@ -3595,9 +3592,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test-prompt',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => ({
|
||||
messages: [
|
||||
|
|
@ -3637,9 +3634,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test-prompt',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: completable(z.string(), () => ['Alice', 'Bob', 'Charlie'])
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => ({
|
||||
messages: [
|
||||
|
|
@ -3678,9 +3675,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test-prompt',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: completable(z.string(), () => ['Alice', 'Bob', 'Charlie'])
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => ({
|
||||
messages: [
|
||||
|
|
@ -3737,9 +3734,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test-prompt',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: completable(z.string(), test => ['Alice', 'Bob', 'Charlie'].filter(value => value.startsWith(test)))
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => ({
|
||||
messages: [
|
||||
|
|
@ -3984,9 +3981,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerPrompt(
|
||||
'test-prompt',
|
||||
{
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
name: z.string().optional()
|
||||
}
|
||||
})
|
||||
},
|
||||
() => ({
|
||||
messages: []
|
||||
|
|
@ -4287,7 +4284,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
{
|
||||
title: 'Team Greeting',
|
||||
description: 'Generate a greeting for team members',
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
department: completable(z.string(), value => {
|
||||
return ['engineering', 'sales', 'marketing', 'support'].filter(d => d.startsWith(value));
|
||||
}),
|
||||
|
|
@ -4307,7 +4304,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
}
|
||||
return ['Guest'].filter(n => n.startsWith(value));
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ department, name }) => ({
|
||||
messages: [
|
||||
|
|
@ -4444,11 +4441,11 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerTool(
|
||||
'book-restaurant',
|
||||
{
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
restaurant: z.string(),
|
||||
date: z.string(),
|
||||
partySize: z.number()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ restaurant, date, partySize }) => {
|
||||
// Check availability
|
||||
|
|
@ -5577,7 +5574,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
{
|
||||
title: 'Team Greeting',
|
||||
description: 'Generate a greeting for team members',
|
||||
argsSchema: {
|
||||
argsSchema: z.object({
|
||||
department: completable(z.string(), value => {
|
||||
return ['engineering', 'sales', 'marketing', 'support'].filter(d => d.startsWith(value));
|
||||
}),
|
||||
|
|
@ -5597,7 +5594,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
}
|
||||
return ['Guest'].filter(n => n.startsWith(value));
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ department, name }) => ({
|
||||
messages: [
|
||||
|
|
@ -5734,11 +5731,11 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
mcpServer.registerTool(
|
||||
'book-restaurant',
|
||||
{
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
restaurant: z.string(),
|
||||
date: z.string(),
|
||||
partySize: z.number()
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ restaurant, date, partySize }) => {
|
||||
// Check availability
|
||||
|
|
@ -6214,9 +6211,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'long-running-task',
|
||||
{
|
||||
description: 'A long running task',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
},
|
||||
}),
|
||||
execution: {
|
||||
taskSupport: 'required'
|
||||
}
|
||||
|
|
@ -6319,9 +6316,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'optional-task',
|
||||
{
|
||||
description: 'An optional task',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
value: z.number()
|
||||
},
|
||||
}),
|
||||
execution: {
|
||||
taskSupport: 'optional'
|
||||
}
|
||||
|
|
@ -6427,9 +6424,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'task-tool',
|
||||
{
|
||||
description: 'A task tool',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
data: z.string()
|
||||
},
|
||||
}),
|
||||
execution: {
|
||||
taskSupport: 'required'
|
||||
}
|
||||
|
|
@ -6737,9 +6734,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'invalid-task',
|
||||
{
|
||||
description: 'A task with forbidden support',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
input: z.string()
|
||||
},
|
||||
}),
|
||||
execution: {
|
||||
taskSupport: 'forbidden' as unknown as 'required'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import {
|
|||
ListToolsResultSchema,
|
||||
McpServer
|
||||
} from '@modelcontextprotocol/server';
|
||||
import type { ZNamespace, ZodMatrixEntry } from '@modelcontextprotocol/test-helpers';
|
||||
import { listenOnRandomPort, zodTestMatrix } from '@modelcontextprotocol/test-helpers';
|
||||
import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
async function setupServer(withSessionManagement: boolean, z: ZNamespace) {
|
||||
async function setupServer(withSessionManagement: boolean) {
|
||||
const server: Server = createServer();
|
||||
const mcpServer = new McpServer(
|
||||
{ name: 'test-server', version: '1.0.0' },
|
||||
|
|
@ -55,9 +55,9 @@ async function setupServer(withSessionManagement: boolean, z: ZNamespace) {
|
|||
'greet',
|
||||
{
|
||||
description: 'A simple greeting tool',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
name: z.string().describe('Name to greet').default('World')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ name }) => {
|
||||
return {
|
||||
|
|
@ -85,8 +85,7 @@ async function setupServer(withSessionManagement: boolean, z: ZNamespace) {
|
|||
return { server, mcpServer, serverTransport, baseUrl };
|
||||
}
|
||||
|
||||
describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
||||
const { z } = entry;
|
||||
describe('Zod v4', () => {
|
||||
describe('Streamable HTTP Transport Session Management', () => {
|
||||
// Function to set up the server with optional session management
|
||||
describe('Stateless Mode', () => {
|
||||
|
|
@ -96,7 +95,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
let baseUrl: URL;
|
||||
|
||||
beforeEach(async () => {
|
||||
const setup = await setupServer(false, z);
|
||||
const setup = await setupServer(false);
|
||||
server = setup.server;
|
||||
mcpServer = setup.mcpServer;
|
||||
serverTransport = setup.serverTransport;
|
||||
|
|
@ -260,7 +259,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
let baseUrl: URL;
|
||||
|
||||
beforeEach(async () => {
|
||||
const setup = await setupServer(true, z);
|
||||
const setup = await setupServer(true);
|
||||
server = setup.server;
|
||||
mcpServer = setup.mcpServer;
|
||||
serverTransport = setup.serverTransport;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
TaskSchema
|
||||
} from '@modelcontextprotocol/server';
|
||||
import { listenOnRandomPort, waitForTaskStatus } from '@modelcontextprotocol/test-helpers';
|
||||
import { z } from 'zod';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
describe('Task Lifecycle Integration Tests', () => {
|
||||
let server: Server;
|
||||
|
|
@ -57,10 +57,10 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
{
|
||||
title: 'Long Running Task',
|
||||
description: 'A tool that takes time to complete',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
duration: z.number().describe('Duration in milliseconds').default(1000),
|
||||
shouldFail: z.boolean().describe('Whether the task should fail').default(false)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ duration, shouldFail }, extra) {
|
||||
|
|
@ -109,9 +109,9 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
{
|
||||
title: 'Input Required Task',
|
||||
description: 'A tool that requires user input',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
userName: z.string().describe('User name').optional()
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ userName }, extra) {
|
||||
|
|
@ -413,9 +413,9 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
{
|
||||
title: 'Multi Request Task',
|
||||
description: 'A tool that sends multiple server requests',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
requestCount: z.number().describe('Number of requests to send').default(3)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ requestCount }, extra) {
|
||||
|
|
@ -902,9 +902,9 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
{
|
||||
title: 'Cancellable Task',
|
||||
description: 'A tool that queues messages and can be cancelled',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
messageCount: z.number().describe('Number of messages to queue').default(2)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ messageCount }, extra) {
|
||||
|
|
@ -1099,10 +1099,10 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
{
|
||||
title: 'Streaming Task',
|
||||
description: 'A tool that sends messages over time',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
messageCount: z.number().describe('Number of messages to send').default(3),
|
||||
delayBetweenMessages: z.number().describe('Delay between messages in ms').default(200)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ messageCount, delayBetweenMessages }, extra) {
|
||||
|
|
@ -1316,9 +1316,9 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
{
|
||||
title: 'Quick Complete Task',
|
||||
description: 'A tool that queues messages and completes quickly',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
messageCount: z.number().describe('Number of messages to queue').default(2)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
async createTask({ messageCount }, extra) {
|
||||
|
|
@ -1622,9 +1622,12 @@ describe('Task Lifecycle Integration Tests', () => {
|
|||
await client.connect(transport);
|
||||
|
||||
// Use callToolStream instead of raw request()
|
||||
const stream = client.experimental.tasks.callToolStream({ name: 'input-task', arguments: {} }, CallToolResultSchema, {
|
||||
task: { ttl: 60_000 }
|
||||
});
|
||||
const stream = client.experimental.tasks.callToolStream(
|
||||
{ name: 'input-task', arguments: {} },
|
||||
{
|
||||
task: { ttl: 60_000 }
|
||||
}
|
||||
);
|
||||
|
||||
// Collect all stream messages
|
||||
const messages: Array<{ type: string; task?: unknown; result?: unknown; error?: unknown }> = [];
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/cli
|
|||
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
||||
import type { EventStore, JSONRPCMessage } from '@modelcontextprotocol/server';
|
||||
import { CallToolResultSchema, McpServer } from '@modelcontextprotocol/server';
|
||||
import type { ZodMatrixEntry } from '@modelcontextprotocol/test-helpers';
|
||||
import { listenOnRandomPort, zodTestMatrix } from '@modelcontextprotocol/test-helpers';
|
||||
import { listenOnRandomPort } from '@modelcontextprotocol/test-helpers';
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
/**
|
||||
* Simple in-memory EventStore for testing resumability.
|
||||
|
|
@ -43,8 +43,7 @@ class InMemoryEventStore implements EventStore {
|
|||
}
|
||||
}
|
||||
|
||||
describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
||||
const { z } = entry;
|
||||
describe('Zod v4', () => {
|
||||
describe('Transport resumability', () => {
|
||||
let server: Server;
|
||||
let mcpServer: McpServer;
|
||||
|
|
@ -64,9 +63,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'send-notification',
|
||||
{
|
||||
description: 'Sends a single notification',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
message: z.string().describe('Message to send').default('Test notification')
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ message }, { sendNotification }) => {
|
||||
// Send notification immediately
|
||||
|
|
@ -89,10 +88,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
'run-notifications',
|
||||
{
|
||||
description: 'Sends multiple notifications over time',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
count: z.number().describe('Number of notifications to send').default(10),
|
||||
interval: z.number().describe('Interval between notifications in ms').default(50)
|
||||
}
|
||||
})
|
||||
},
|
||||
async ({ count, interval }, { sendNotification }) => {
|
||||
// Send notifications at specified intervals
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
import { Client } from '@modelcontextprotocol/client';
|
||||
import { InMemoryTransport } from '@modelcontextprotocol/core';
|
||||
import { McpServer, ResourceTemplate, Server } from '@modelcontextprotocol/server';
|
||||
import type { ZodMatrixEntry } from '@modelcontextprotocol/test-helpers';
|
||||
import { zodTestMatrix } from '@modelcontextprotocol/test-helpers';
|
||||
|
||||
describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
||||
const { z } = entry;
|
||||
import * as z from 'zod/v4';
|
||||
|
||||
describe('Zod v4', () => {
|
||||
describe('Title field backwards compatibility', () => {
|
||||
it('should work with tools that have title', async () => {
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
|
|
@ -19,9 +16,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
{
|
||||
title: 'Test Tool Display Name',
|
||||
description: 'A test tool',
|
||||
inputSchema: {
|
||||
inputSchema: z.object({
|
||||
value: z.string()
|
||||
}
|
||||
})
|
||||
},
|
||||
async () => ({ content: [{ type: 'text', text: 'result' }] })
|
||||
);
|
||||
|
|
@ -44,7 +41,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
const server = new McpServer({ name: 'test-server', version: '1.0.0' }, { capabilities: {} });
|
||||
|
||||
// Register tool without title
|
||||
server.registerTool('test-tool', { description: 'A test tool', inputSchema: { value: z.string() } }, async () => ({
|
||||
server.registerTool('test-tool', { description: 'A test tool', inputSchema: z.object({ value: z.string() }) }, async () => ({
|
||||
content: [{ type: 'text', text: 'result' }]
|
||||
}));
|
||||
|
||||
|
|
@ -94,7 +91,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
{
|
||||
title: 'Test Prompt Display Name',
|
||||
description: 'A test prompt',
|
||||
argsSchema: { input: z.string() }
|
||||
argsSchema: z.object({ input: z.string() })
|
||||
},
|
||||
async ({ input }) => ({
|
||||
messages: [
|
||||
|
|
|
|||
Loading…
Reference in a new issue