SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12 - #1135

Merged
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613
Nov 21, 2025
Merged

SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12#1135
pcarleton merged 6 commits into
mainfrom
fweinberger/sep-1613

Conversation

@felixweinberger

@felixweinbergerfelixweinberger commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Summary

Restores .catchall() on inputSchema and outputSchema in ToolSchema to properly support JSON Schema 2020-12 keywords as required by SEP-1613.

Motivation and Context

SEP-1613 establishes JSON Schema 2020-12 as the default dialect for MCP embedded schemas. This requires the SDK to preserve all JSON Schema properties (like $schema, additionalProperties, $defs, allOf, etc.) rather than stripping them.

The Problem: PR #1086 removed .passthrough() from ToolSchema, causing the SDK to strip valid JSON Schema properties. This was reported in #1057 where $schema was being stripped, breaking SEP-1613's backwards compatibility mechanism (servers need $schema to specify alternative dialects).

Why passthrough is correct here:

  1. Spec compliance: The MCP spec's JSON Schema for inputSchema does NOT have additionalProperties: false, meaning additional properties are allowed by default
  2. inputSchema is an external spec: Unlike MCP protocol fields, inputSchema/outputSchema are JSON Schema objects - the SDK should transport them, not validate their internal structure
  3. SEP-1613 backwards compatibility: Servers must be able to specify $schema to use dialects other than 2020-12
  4. Restores original behavior: The SDK had passthrough before PR SEP-1319: Decouple Request Payloads, Remove passthrough iteration, Typecheck fixes #1086

Changes:

  • Add .catchall() to inputSchema and outputSchema in ToolSchema
  • Preserve existing typed properties (type, properties, required) for TypeScript backwards compatibility
  • Add JSDoc documenting SEP-1613/2020-12 default dialect
  • Add comprehensive tests for JSON Schema 2020-12 keyword acceptance

How Has This Been Tested?

  • Added unit tests ensuring required fields are passed through.

Breaking Changes

None. This restores the ability to use JSON Schema properties that were being silently stripped since PR #1125.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@felixweinberger
felixweinberger requested a review from a team as a code ownerNovember 18, 2025 23:18
Add .passthrough() to inputSchema and outputSchema to accept all JSON Schema
2020-12 keywords. This is the correct approach because:
- inputSchema/outputSchema are embedded external specs (JSON Schema), not
MCP protocol fields that should be strictly validated
- The SDK's role is to transport schemas, not validate JSON Schema structure
- Enumeration approach would silently drop unrecognized keywords (data loss)
Changes:
- Add .passthrough() to inputSchema and outputSchema in ToolSchema
- Update JSDoc to document SEP-1613/2020-12 as default dialect
- Add comprehensive tests for JSON Schema 2020-12 keyword support
Backwards compatible: existing typed properties (type, properties, required)
remain explicitly typed for TypeScript autocomplete.
@pkg-pr-new

pkg-pr-newBot commented Nov 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1135

commit: d3dfd94

@KKonstantinov

Copy link
Copy Markdown
Contributor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

More semantically correct for JSON Schema objects where additional
properties are expected but not validated by Zod.
@felixweinberger

Copy link
Copy Markdown
ContributorAuthor

Hello,

There should be a way to achieve it without using .passthrough() and without necessarily listing all the possible fields.

.catchall(z.unknown) should achieve the same effect:

inputSchema: z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}).catchall(z.unknown()),

or alternatively an intersection with a Record<string, unknown>

 inputSchema: z.intersection(z.object({type: z.literal('object'),properties: z.record(z.string(),AssertObjectSchema).optional(),required: z.array(z.string()).optional()}),z.record(z.string(),z.unknown()))

Done!

@felixweinberger
felixweinberger requested review from KKonstantinov and removed request for KKonstantinovNovember 20, 2025 14:43
@felixweinbergerfelixweinberger changed the title SEP-1613: Restore passthrough for inputSchema/outputSchema to support JSON Schema 2020-12SEP-1613: use.catchall() on inputSchema/outputSchema to support JSON Schema 2020-12Nov 20, 2025
@pcarleton
pcarleton merged commit 41c6b35 into mainNov 21, 2025
10 checks passed
@pcarleton
pcarleton deleted the fweinberger/sep-1613 branch November 21, 2025 13:41
pcarleton added a commit that referenced this pull request Jan 12, 2026
- Remove unused Tool type import
- Remove unused JSON_SCHEMA_2020_12_INPUT_SCHEMA constant
(SEP-1613 test is pending - SDK validation supports the fields via PR #1135,
but tool registration doesn't yet support generating raw JSON Schema)
- Remove emoji from console.log
- Alphabetize devDependencies in package.json
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-1613: JSON Schema 2020-12 as Default Dialect

3 participants

@felixweinberger@KKonstantinov@pcarleton