Skip to content

bug(search_compounds): mode-specific fields are optional in the advertised schema, so searchType alone passes validation and fails in the handler #45

Description

@cyanheads

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

  1. Call pubchem_search_compounds with { "searchType": "identifier" }.
  2. Schema validation passes.
  3. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions