Aident AI

MCP TypeScript inputSchema Empty? Fix z.object on v1
If a TypeScript MCP server publishes an empty tool inputSchema, check the SDK major version and the registration API before changing the client. Legacy v1 server.tool() expects a raw Zod shape such as { name: z.string() }. The v2 registerTool() API expects a Standard Schema such as z.object({ name: z.string() }).
Using the v2 form on an affected v1 positional server.tool() call can publish {"type":"object"} with no properties, strip every argument before the handler, or fail tools/list with an internal _def error. Use the schema form that matches the installed SDK, reconnect the client, and verify the actual tools/list response.
This guide is specifically about the TypeScript SDK's raw-shape versus ZodObject boundary. If tools/list already contains the correct fields but a client sends one object as a quoted string, use the separate empty property schema guide.
Recognize the Version-Mismatch Signature
Match all of these conditions:
the server uses the TypeScript MCP SDK;
the tool is registered with
server.tool()orserver.registerTool();source code declares one or more input fields;
the discovered top-level
inputSchemahas noproperties, ortools/listfails while converting the schema; andthe handler receives
{}or never receives a valid call.
A current upstream report tested the failure across v1 releases. On older v1 versions, a ZodObject supplied to the wrong legacy overload could either crash tools/list or silently produce an empty object schema. More recent v1 releases improved normalization and errors, but the v1 and v2 contracts still differ.
Do not diagnose this from TypeScript source alone. The contract the model sees is the JSON Schema returned by tools/list.
Check the Installed Package and API
Start with a clean working tree and identify the package actually resolved by the server:
Then inspect the registration call.
The legacy v1 positional form looks like this:
On an affected v1 path, z.object(...) is the wrong schema form for that position. Do not assume it is correct just because it is idiomatic Zod or appears in v2 documentation.
The v2 form uses a configuration object:
That z.object(...) is the native v2 contract. Swapping the forms without checking the installed major version can move the bug rather than fix it.
Fix a v1 server.tool Call With a Raw Shape
For the affected v1 positional API, pass the raw shape directly:
Keep one source of truth. Do not retain a raw shape for discovery and a separate z.object(...) for runtime validation. The registration API should derive both discovery metadata and handler validation from the same definition.
Rebuild the server with its owning package command, stop the old process, and reconnect the client. A source edit does not prove that the running process or current client session has rediscovered the tool.
Expected result:
If the discovered schema still lacks name, stop. You may be rebuilding a different package, launching an older output directory, or reconnecting to another server command.
Migrate to v2 Without Inverting the Fix
The official v1-to-v2 guide recommends running the codemod first, then reviewing every marker and type error. The codemod replaces legacy registration calls and wraps raw input shapes in z.object(...) for the v2 API.
Run it only on a reviewable branch:
Review the diff before accepting it. The migration changes package imports, registration APIs, handler context, transports, errors, and other contracts beyond schemas. Do not manually wrap every raw shape before running the codemod, because that makes the source harder to classify and can recreate the v1 failure before the package migration lands.
After migration, the intended v2 pattern is:
Expected result: the v2 package type-checks, tools/list advertises name, a valid call reaches the handler, and an invalid call fails before the handler runs.
Add a Discovery Contract Test
A handler unit test cannot detect a broken advertised schema if it calls the function directly. Add an in-memory client test that exercises the protocol boundary:
Also test a missing name. It should return a validation error and must not enter a side-effecting handler.
This test protects the entire path:
Separate Similar Empty-Schema Bugs
An empty schema has more than one possible cause.
Discovered behavior | Likely boundary | Next action |
|---|---|---|
v1 | Raw shape versus | Pass the v1 raw shape or migrate the whole registration to v2 |
v2 | v1 syntax retained during migration | Run and review the official codemod, then use a Standard Schema |
Plain fields work, but | Wrapped Zod schema conversion | Track the separate ZodEffects issue and do not claim the raw-shape fix covers it |
Top-level fields are correct, but one property schema is | Untyped property contract | Follow the stringified argument guide |
| Client generation, transport, or application parsing | Capture the raw |
The TypeScript SDK has separate reports for discriminated unions and ZodEffects wrappers. Do not flatten a union or remove cross-field validation merely to make an empty schema disappear. Reduce the case to a plain object, identify the failing wrapper, and follow the matching upstream issue.
Common Mistakes
Copying v2 documentation into a v1 server
Current v2 examples correctly use z.object(...). They are not evidence that the same value belongs in every v1 overload.
Patching the client
The client cannot infer fields that the server omitted from discovery. Fix the server contract first, then reconnect.
Parsing {} in the handler
Adding defaults or manually decoding arguments hides the missing discovery contract. The model still cannot see the fields, and invalid input may reach a write.
Keeping two schema definitions
Two definitions drift. Use the registration API's supported schema value as the shared source for discovery and validation.
Calling migration complete after the codemod
The codemod is a mechanical first pass. Type-check, inspect every marker, run protocol tests, and verify the deployed server command.
Verify Upstream State With Aident Loadout
Start with the canonical setup instruction:
Follow https://aident.ai/SETUP.md
Then give your agent this bounded request:
Check Aident Loadout authentication and Vault status. Search the staging capability catalog for the current read-only GitHub issue lookup Action, inspect its schema, and preflight exact lookups for modelcontextprotocol/typescript-sdk issues 2627, 1291, and 2145. If every estimate is valid and free, execute the lookups and return only issue number, state, updated time, title, comment count, labels, and canonical URL. Do not comment, react, edit, close, create, install, change files, or expose credentials.
The measurable result is three current issue records and zero provider writes. Use that check before repeating an old workaround in a release note or support reply.
Set up Aident Loadout and verify the MCP schema issues read-only.
For a smaller tool surface before debugging, use How to Reduce MCP Token Usage in Claude Code and Codex. For another version-sensitive SDK migration, see MCP Python SDK 2 McpError ImportError.
Sources
MCP TypeScript SDK issue 2627: v1 z.object can empty inputSchema or crash tools/list
MCP TypeScript SDK issue 1291: server.tool silently ignored ZodObject schemas
MCP TypeScript SDK issue 2145: ZodEffects wrappers can publish an empty schema
MCP TypeScript SDK pull request 1901: raw-shape compatibility in v2
Refresh this guide when issue 2627 changes state, the recommended v1 release changes its schema normalization, the v2 registration contract changes, or issue 2145 receives a released fix.



The one tool
for every tool
your agent needs.
Give any AI agent real capabilities in seconds. Connect 1,000+ tools once, skip the setup headache, and let your agents execute.
