fix: flatten MCP query tool schema so SDK serializes inputSchema correctly#2124
fix: flatten MCP query tool schema so SDK serializes inputSchema correctly#2124brandon-pereira wants to merge 2 commits intomainfrom
Conversation
The MCP SDK's normalizeObjectSchema() only recognizes plain z.object() schemas. Using z.discriminatedUnion() wraps the schema in a type the SDK silently replaces with an empty schema in the tools/list response -- making the tool unusable for MCP clients. Replaced the discriminated union with a flat z.object() for SDK serialization and a separate validateQueryInput() function for cross-field validation at runtime. Added a regression test that verifies the schema properties are properly exposed via tools/list.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 680e7ff The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🟡 Tier 3 — StandardIntroduces new logic, modifies core functionality, or touches areas with non-trivial risk. Why this tier:
Review process: Full human review — logic, architecture, edge cases. Stats
|
PR ReviewFix for MCP SDK silently dropping non-plain
|
E2E Test Results✅ All tests passed • 132 passed • 3 skipped • 1064s
Tests ran across 4 shards in parallel. |
Summary
During code review on the original MCP PR (#2030), the
hyperdxQuerySchemawas refactored from a flat object into az.discriminatedUnion()to reduce duplication and improve type safety. This inadvertently broke the tool's parameter schema — the MCP SDK'snormalizeObjectSchema()only recognizes plainz.object()schemas and silently replaces anything else (discriminated unions,ZodEffectsfrom.superRefine/.refine/.transform) with an empty{}in thetools/listresponse, making the tool unusable for MCP clients.Changes:
z.discriminatedUnion()with a single flatz.object()that the SDK can serializevalidateQueryInput()function called at runtime in the handlertools/listand asserts all expected properties (displayType,sourceId,select,where,sql,connectionId, etc.) are present in the serializedinputSchemaHow to test locally or on Vercel
yarn devtools/list— verifyhyperdx_queryexposes all properties (displayType,sourceId,select,where,sql, etc.) instead of an empty schemacd packages/api && yarn ci:unit src/mcp/__tests__/queryTool.test.tsReferences