Skip to content

Support JSON schema in addition to zod #283

Closed

Description

@psclkhoury

Why dont you add support for jsonschema in addition to zod. A lot of projects already have jsonshemas defined and you are converting internally from zod to jsonschema.

Activity

  1. added
    enhancementRequest for a new feature that's not currently supported
    on Apr 7, 2025
  2. changed the title [-]Support JSON schema in addition to sod[/-] [+]Support JSON schema in addition to zod[/+] on Apr 11, 2025
  3. ThomasAribart commented on May 26, 2025

    @ThomasAribart

    I guess this is for type-safety/devX. However there are tools for type inference like https://github.com/ThomasAribart/json-schema-to-ts.

  4. tianlinle commented on Jun 23, 2025

    @tianlinle

    I'm also looking forward to JSON-Schema. @ThomasAribart It's not for type-safety, it's the same goal as zod. Right now I'm using ajv to validate any JSON data by JSON-Schema. Tool calling in most LLMs is using JSON-schema to describe the args of a function, so I think it's helpful if MCP also can support JSON-Schema in addition to zod.

  5. finom commented on Jun 28, 2025

    @finom

    After creating vercel-labs/mcp-handler#65 and digging thru the source codes I found this repository. I'm using @vercel/mcp-adapter and all I have is JSON Schema. My attempts to convert it to Zod were unsuccessful.

    It seems like the SDK supports Zod 3 only with legacy zod-to-json-schema, even though there is a plenty of libraries, including Zod 4, Valibot and other libraries that implement Standard Schema and their own toJSONSchema first-, second-, or 3rd-party implementation. IMO, such an important SDK should be JSON Schema-first, instead of one-legacy-library-first, even though Zod 3 is still maintained.

    Ajv has a nice TypeScript library that might be a great fit to support JSON Schemas. At this case the SDK can support basically all modern validation libraries, instead of one specific version of one specific library.

  6. Rutledge commented on Jun 28, 2025

    @Rutledge

    +1 for JSON Schema support. I'm currently blocked by this when using Stainless-generated MCP
    tools.

    Stainless (and many other code generators) produce plain JSON schemas from OpenAPI specs.
    When these are passed to server.tool(), the MCP SDK tries to run zodToJsonSchema() on
    them, which fails because they're already JSON schemas, not Zod schemas.

    This results in:

    • Parameters not showing up in MCP Inspector
    • Tools receiving undefined for all parameters
    • The actual parameter schema appearing in the wrong place (e.g., in annotations instead of
      inputSchema)

    Supporting plain JSON schemas would enable:

    1. Code-generated tools from OpenAPI specs
    2. Integration with existing JSON Schema tooling
    3. Compatibility with other validation libraries beyond Zod

    Related issue in Vercel adapter: vercel-labs/mcp-handler#65

  7. priolo commented on Jul 27, 2025

    @priolo

    +1 for JSON Schema support.
    Transforming from JSON Schema to ZOD is not easy.

  8. emaciel10 commented on Aug 6, 2025

    @emaciel10

    Completely agreed, going from json schema to a clean zod schema has been a pain for us so having MCPServer work with just json schema would be great!

  9. bahatron commented on Sep 24, 2025

    @bahatron

    We use https://github.com/sinclairzx81/typebox for types, the runtime object is a normal valid jsonschema object. Would be nice to be able to give it valid jsonschema coming from typebox

  10. logseq-cldwalker commented on Sep 25, 2025

    @logseq-cldwalker

    We're using this library from clojurescript and already have json schemas created by https://github.com/metosin/malli. We'd love to be able to reuse these json schemas without having to maintain a separate zod version of them

  11. dan-kwiat commented on Oct 5, 2025

    @dan-kwiat

    I agree it would be nice to have the option of using JSON Schema in the helpers registerTool, registerPrompt etc. and I'd be happy to implement it. But FYI you can already work with JSON Schema through the low-level server:

    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
    import {
      ListToolsRequestSchema,
      CallToolRequestSchema,
    } from "@modelcontextprotocol/sdk/types.js"
    
    const server = new McpServer(
      {
        name: "example-server",
        version: "1.0.0",
      },
      {
        capabilities: {
          tools: {
            listChanged: false,
          },
        },
      }
    )
    
    server.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "echo",
            title: "Echo Tool",
            description: "Echoes back the provided message",
            inputSchema: {
              type: "object",
              properties: {
                message: {
                  type: "string",
                  description: "The message to echo back",
                },
              },
              required: ["message"],
            },
            outputSchema: {
              type: "object",
              properties: {
                echo: { type: "string", description: "The echoed message" },
              },
              required: ["echo"],
            },
          },
        ],
      }
    })
    
    server.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      if (request.params.name !== "echo") {
        throw new Error(`Unknown tool: ${request.params.name}`)
      }
    
      const args = request.params.arguments as any
    
      // Validate args against inputSchema here
    
      const output = { echo: `Tool echo: ${args.message}` }
    
      return {
        content: [{ type: "text", text: JSON.stringify(output) }],
        structuredContent: output,
      }
    })
  12. added
    P3Nice to haves, rare edge cases
    P2Moderate issues affecting some users, edge cases, potentially valuable feature
    and removed
    P3Nice to haves, rare edge cases
    on Nov 3, 2025
  13. finom commented on Nov 14, 2025

    @finom

    I'm working on a project that requires supporting a lot of libraries out of the box but also convertion to JSON Schema. There is my proposal for solving this problem.

    There are two key limitations in today's ecosystem:

    1. Standard Schema does not provide toJSONSchema

    This is intentional to keep package sizes small. Libraries like Valibot ship JSON Schema support as separate packages (e.g., @valibot/to-json-schema).

    2. JSON Schema validators do not understand Standard Schema

    There is no JSON Schema validator that accepts Standard Schema directly.


    ✅ Proposed Solution

    1. A new Ajv-based Standard Schema implementation

    Introduce a function that implements the Standard Schema interface using Ajv internally.

    import { ajvStandardSchema } from "standard-schema-ajv"; // doesn't exist yet
    const ajvStandard = ajvStandardSchema<MyData>({
      type: "object",
      properties: {
        foo: { type: "integer" },
        bar: { type: "string", nullable: true }
      },
      required: ["foo"],
      additionalProperties: false
    });
    
    ajvStandard.schema; // The same JSON Schema above
    
    ajvStandard['~standard'].validate({ foo: 123 });

    2. A universal adapter

    Introduce a function that wraps any Standard Schema implementation and adds JSON Schema conversion capabilities.

    import {
      createStandardSchemaWithJsonSchemaValidation
    } from "standard-schema-to-json-schema"; // doesn't exist yet
    
    // Zod example
    import { z } from "zod";
    
    const validator = createStandardSchemaWithJsonSchemaValidation({
      toJSONSchema: (model) => z.toJSONSchema(model),
    });
    
    const model = validator(
      z.object({
        foo: z.number().int(),
        bar: z.string().nullable()
      })
    );
    
    model['~standard'].validate({ foo: 123 });
    model.toJSONSchema();
    
     
    // Ajv example
    
    import { ajvStandardSchema } from "standard-schema-ajv"; // doesn't exist yet
    
    const validator = createStandardSchemaWithJsonSchemaValidation({
      toJSONSchema: (model) => model.schema,
    });
    
    const model = validator(
      ajvStandardSchema({
        type: "object",
        properties: {
          foo: { type: "integer" },
          bar: { type: "string", nullable: true }
        },
        required: ["foo"],
        additionalProperties: false
      })
    );
    
    model['~standard'].validate({ foo: 123 });
    model.toJSONSchema();
    
    // Valibot example
    import { toJsonSchema } from '@valibot/to-json-schema';
    import * as v from "valibot";
    
    const validator = createStandardSchemaWithJsonSchemaValidation({
      toJSONSchema: (model) => toJsonSchema(model),
    });
    
    const model = validator(
      v.object({
        email: v.string(),
        password: v.string()
      })
    );
    
    model['~standard'].validate({
      email: "user@example.com",
      password: "securepassword"
    });
    
    model.toJSONSchema();

    In the context of MCP SDK this may look like:

    const validator = createStandardSchemaWithJsonSchemaValidation({ toJSONSchema: ... });
    
    // Zod example
    server.registerTool(
        'add',
        {
            title: 'Addition Tool',
            description: 'Add two numbers',
            inputSchema: { a: validator(z.number()), b: validator(z.number()) },
            outputSchema: { result: validator(z.number()) }
        },
        async ({ a, b }) => {
           // ...
        }
    );
    
    // Ajv example (raw JSON schema)
    server.registerTool(
        'add',
        {
            title: 'Addition Tool',
            description: 'Add two numbers',
            inputSchema: { a: validator({ type: "integer" }), b: validator({ type: "integer" }) },
            outputSchema: { result: validator({ type: "integer" }) }
        },
        async ({ a, b }) => {
           // ...
        }
    );
    
    // Valibot example
    server.registerTool(
        'add',
        {
            title: 'Addition Tool',
            description: 'Add two numbers',
            inputSchema: { a: validator(v.number()), b: validator(v.number()) },
            outputSchema: { result: validator(v.number()) }
        },
        async ({ a, b }) => {
           // ...
        }
    );

    I could take care of implementing this if the proposal looks good to you. Let me know your thoughts.

  14. added this to the v2 milestone on Dec 5, 2025
  15. KKonstantinov commented on Dec 5, 2025

    @KKonstantinov
    Contributor

    Adding this to #809

  16. ghost removed
    P2Moderate issues affecting some users, edge cases, potentially valuable feature
    on Apr 17, 2026
  17. ghost added
    needs decisionIssue is actionable, needs maintainer decision on whether to implement
    on Apr 17, 2026
  18. ghost added
    P1Significant bug affecting many users, highly requested feature
    on Apr 17, 2026
  19. ghost added
    v2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes
    on Apr 17, 2026
  20. felixweinberger commented on Oct 5, 2026

    @felixweinberger
    Contributor

    v2 takes tool schemas from any Standard Schema library that can produce JSON Schema, and fromJsonSchema() wraps a plain JSON Schema you already have (#1689, released in 2.0.0). v1 stays on Zod for registerTool(); the low-level setRequestHandler route shown above works there. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Significant bug affecting many users, highly requested featureenhancementRequest for a new feature that's not currently supportedneeds decisionIssue is actionable, needs maintainer decision on whether to implementv2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions