Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/server/__tests__/vendor/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as _zod from 'zod';

// This makes the vendored zod use the same types as the actual zod package
export declare const z: typeof _zod.z;
export default _zod.default;
8 changes: 8 additions & 0 deletions src/server/__tests__/vendor/[email protected]

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/server/mcp.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { McpServer } from "./mcp.js";
import { Client } from "../client/index.js";
import { InMemoryTransport } from "../inMemory.js";
import { z } from "zod";
import {
ListToolsResultSchema,
CallToolResultSchema,
Expand All @@ -17,6 +16,9 @@ import {
import { ResourceTemplate } from "./mcp.js";
import { completable } from "./completable.js";
import { UriTemplate } from "../shared/uriTemplate.js";
// Note: deliberately using a different Zod version to the one bundled
// with the SDK as that's what our users are likely to be doing
import { z } from "./__tests__/vendor/[email protected]";

describe("McpServer", () => {
test("should expose underlying Server instance", () => {
Expand Down
29 changes: 19 additions & 10 deletions src/server/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,16 +659,6 @@ export class McpServer {
if (this._registeredTools[name]) {
throw new Error(`Tool ${name} is already registered`);
}

// Helper to check if an object is a Zod schema (ZodRawShape)
const isZodRawShape = (obj: unknown): obj is ZodRawShape => {
if (typeof obj !== "object" || obj === null) return false;

const isEmptyObject = z.object({}).strict().safeParse(obj).success;

// Check if object is empty or at least one property is a ZodType instance
return isEmptyObject || Object.values(obj as object).some(v => v instanceof ZodType);
};

let description: string | undefined;
if (typeof rest[0] === "string") {
Expand Down Expand Up @@ -931,6 +921,25 @@ const EMPTY_OBJECT_JSON_SCHEMA = {
type: "object" as const,
};

// Helper to check if an object is a Zod schema (ZodRawShape)
function isZodRawShape(obj: unknown): obj is ZodRawShape {
if (typeof obj !== "object" || obj === null) return false;

const isEmptyObject = z.object({}).strict().safeParse(obj).success;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haven't tested it, would it potentially also cause an issue with a different version of Zod?


// Check if object is empty or at least one property is a ZodType instance
return isEmptyObject || Object.values(obj as object).some(isZodType);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isZodType(value: any): value is ZodType {
return value !== null &&
typeof value === 'object' &&
typeof value.parse === 'function' &&
typeof value.safeParse === 'function' &&
typeof value._def === 'object';
}

/**
* Additional, optional information for annotating a resource.
*/
Expand Down
Loading