Server version
0.6.0
mcp-ts-core version
0.10.17
Runtime
Bun
Runtime version
Bun 1.3.14
Transport
stdio, http
Description
pubchem_search_compounds advertises searchType as a flat z.enum while every mode-specific field is optional, so the published inputSchema accepts a call that the handler is guaranteed to reject.
In src/mcp-server/tools/definitions/search-compounds.tool.ts, identifierType, identifiers, and formula are all optional. { "searchType": "identifier" } with nothing else therefore passes schema validation, reaches the handler, and throws:
case 'identifier': {
const { identifierType, identifiers } = input;
if (!identifierType || !identifiers) {
// -> ctx.fail('missing_identifiers')
The requirement is carried only in .describe() prose — "Required for identifier search" on identifiers, "Required for formula search" on formula. Prose in a field description is advisory; a caller generating arguments from the JSON Schema sees three independent optional fields and no structural link to the searchType it picked. formula mode has the identical gap (missing_formula).
Steps to reproduce
- Call
pubchem_search_compounds with { "searchType": "identifier" }.
- Schema validation passes.
- The handler throws
missing_identifiers.
Same with { "searchType": "formula" } → missing_formula.
Actual behavior
An input the advertised schema declares valid fails at runtime. The error and its recovery hint are both well-formed, but the round trip is avoidable — the schema could have made the combination unrepresentable.
Expected behavior
Either the schema encodes the coupling, or the descriptions make the requirement impossible to miss from the schema alone.
| Option |
Strengths |
Weaknesses |
A — z.discriminatedUnion on searchType |
Structurally unrepresentable; serializes to JSON Schema oneOf, so the constraint reaches the caller |
Changes the advertised inputSchema shape for an existing tool; oneOf support varies across clients |
| B — sharpen the descriptions |
No schema change, no client-compat risk |
Still advisory; no structural guarantee |
C — superRefine on the flat object |
Better server-side message |
Zod refinements do not serialize, so the published JSON Schema is unchanged — no caller-visible improvement |
C is not worth doing alone: it improves nothing a caller can see. A is the real fix; B is the zero-risk fallback. A changes an existing tool's advertised schema, so it is a contract decision rather than a drop-in patch.
Scope
src/mcp-server/tools/definitions/search-compounds.tool.ts — input schema and the identifier / formula handler branches
- Existing
missing_identifiers and missing_formula error-contract entries stay as defense in depth
Out of scope
- The
substructure / superstructure / similarity modes, which take their query through already-required fields
- The same optional-fields-with-runtime-coupling shape in other tools in this repo — worth a separate sweep if A is adopted here
Server version
0.6.0
mcp-ts-core version
0.10.17
Runtime
Bun
Runtime version
Bun 1.3.14
Transport
stdio, http
Description
pubchem_search_compoundsadvertisessearchTypeas a flatz.enumwhile every mode-specific field is optional, so the publishedinputSchemaaccepts a call that the handler is guaranteed to reject.In
src/mcp-server/tools/definitions/search-compounds.tool.ts,identifierType,identifiers, andformulaare all optional.{ "searchType": "identifier" }with nothing else therefore passes schema validation, reaches the handler, and throws:The requirement is carried only in
.describe()prose — "Required for identifier search" onidentifiers, "Required for formula search" onformula. Prose in a field description is advisory; a caller generating arguments from the JSON Schema sees three independent optional fields and no structural link to thesearchTypeit picked.formulamode has the identical gap (missing_formula).Steps to reproduce
pubchem_search_compoundswith{ "searchType": "identifier" }.missing_identifiers.Same with
{ "searchType": "formula" }→missing_formula.Actual behavior
An input the advertised schema declares valid fails at runtime. The error and its recovery hint are both well-formed, but the round trip is avoidable — the schema could have made the combination unrepresentable.
Expected behavior
Either the schema encodes the coupling, or the descriptions make the requirement impossible to miss from the schema alone.
z.discriminatedUniononsearchTypeoneOf, so the constraint reaches the callerinputSchemashape for an existing tool;oneOfsupport varies across clientssuperRefineon the flat objectC is not worth doing alone: it improves nothing a caller can see. A is the real fix; B is the zero-risk fallback. A changes an existing tool's advertised schema, so it is a contract decision rather than a drop-in patch.
Scope
src/mcp-server/tools/definitions/search-compounds.tool.ts— input schema and theidentifier/formulahandler branchesmissing_identifiersandmissing_formulaerror-contract entries stay as defense in depthOut of scope
substructure/superstructure/similaritymodes, which take their query through already-required fields