- Remove tool() overload that takes a config object with callback
- Add new registerTool() method that separates config from callback
- Extract common tool registration logic into _createRegisteredTool() helper
- Update all tests to use registerTool() for tools with output schemas
- Update examples to use registerTool() and high-level Client API
- Add comment noting that output schema validation only works with high-level API
This change improves API clarity by using a distinct method for tools with
output schemas while maintaining backward compatibility.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update McpServer to support registering tools with outputSchema
- Add automatic content generation from structuredContent for backward compatibility
- Add validation to ensure proper usage of structuredContent vs content
- Add comprehensive tests for outputSchema functionality
- Add example servers demonstrating structured output usage
- Update existing test to match new backward compatibility behavior
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add outputSchema field to Tool type and RegisteredTool interface
- Make content field optional in CallToolResult
- Update ListToolsRequestSchema handler to include outputSchema in tool list responses
- Add support for structuredContent in tool results
- Update examples to handle optional content field
- Add tests for new outputSchema and structuredContent functionality
- Update ToolCallback documentation to clarify when to use structuredContent vs content
This change enables tools to define structured output schemas and return
structured JSON content, providing better type safety and validation for
tool outputs.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- simpler test for empty object
- only test public zod properties (parse, safeParse)
Confirmed that vendored-library tests still pass. Note that you need the --testPathIgnorePatterns to avoid the __tests__ directory (this is what was breaking the build):
$ npm test -- --testPathIgnorePatterns="vendor"
Previously, this check was `value instanceof ZodType`, which breaks if
the user is using a different version of Zod than the library. Instead,
do the check using the structure of the input object rather than its
prototype chain.
Additionally, this adds a vendored version of Zod to use for tests, which
ensures that regressions like this would be caught next time.
This change enables the strictUnions option in zod-to-json-schema so
that any union members that cannot be resolved are excluded from the
resulting JSON Schema anyOf array.
Previously, a schema like this:
**Before**
```ts
import { zodToJsonSchema } from "zod-to-json-schema";
import { z } from "zod";
console.dir(
zodToJsonSchema(
z.union([
z
.string()
.base64()
.transform((v) => Uint8Array.from(atob(v), (v) => v.charCodeAt(0))),
z.instanceof(ReadableStream<Uint8Array>),
z.instanceof(Blob),
z.instanceof(ArrayBuffer),
z.instanceof(Uint8Array),
])
),
{ depth: null }
);
```
Prints:
```js
{
anyOf: [
{ type: "string", contentEncoding: "base64" }, {}, {}, {}, {}
],
$schema: "http://json-schema.org/draft-07/schema#",
}
```
**After**
```ts
import { zodToJsonSchema } from "zod-to-json-schema";
import { z } from "zod";
console.dir(
zodToJsonSchema(
z.union([
z
.string()
.base64()
.transform((v) => Uint8Array.from(atob(v), (v) => v.charCodeAt(0))),
z.instanceof(ReadableStream<Uint8Array>),
z.instanceof(Blob),
z.instanceof(ArrayBuffer),
z.instanceof(Uint8Array),
]),
{ strictUnions: true }, // 👈
),
{ depth: null }
);
```
Prints:
```js
{
anyOf: [
{ type: "string", contentEncoding: "base64" }
],
$schema: "http://json-schema.org/draft-07/schema#",
}
```
---
I picked this example in particular because I have modelled file uploads
using a permissive schema that accepts streams, byte arrays / blobs and
base64-encoded strings. In the context of MCP, base64 would be most
applicable so I wanted to drop the other union members that couldn't be
represented in JSON Schema.
Request handlers were being re-registered every time a new tool/resource/prompt was added, which would fail since the handlers were already registered. Now we track whether handlers have been initialized and only register them once.
Added tests to verify that multiple registrations work correctly.
Resolves#124.