Closes cyanheads/pubmed-mcp-server#46.
Both tools were enforcing cross-field input shape constraints with imperative
`throw new Error(...)` after schema parsing, so violations leaked as JSON-RPC
-32603 Internal error (with level-50 server logs) instead of -32602 Invalid
params. Production telemetry on fetch_fulltext showed 13 unrelated sessions
hitting this in a 30-minute window.
- pubmed_fetch_fulltext: XOR pmcids/pmids check moved from handler into a
.refine() on the input object. describe() text updated on both fields.
- pubmed_lookup_citation: same anti-pattern fixed — "at least one
bibliographic field" check moved into a per-item .refine() on the citation
schema. Errors now include path: ["citations", N] so callers learn which
array index failed.
- Tests updated to assert on input.safeParse() failure rather than handler
rejection.
Field-tested against the live HTTP server: invalid inputs return -32602 with
the new messages, valid paths intact, zero level-50 errors in server logs.
462 tests passing (4 skipped). devcheck green across 11 checks.