fix(manage_frontmatter): type value input as a union so clients serialize structured values correctly#69
Open
tommygents wants to merge 1 commit into
Conversation
…ialize structured values correctly The `set` value input was typed `z.unknown()`, so the rendered JSON Schema for the field carries no `type`. MCP clients that infer wire serialization from the schema (e.g. Claude Code) then send non-string values as their JSON-string form; the handler stringifies again before PATCHing, yielding a double-encoded result — `42` stored as `"42"` (type lost), `["a","b"]` stored as the string `'["a","b"]'`. Strings are unaffected because stringify+parse is identity for a bare string. This is the unresolved tail of cyanheads#20/cyanheads#21/cyanheads#54. The existing unit tests can't catch this: they call `input.parse()` with native JS values, bypassing the client transport where the mis-serialization happens. Verified end-to-end against a live Obsidian Local REST API with the Claude Code MCP client — pre-fix: number/array/object double-encode; post-fix: all JSON types round-trip correctly. Fix: replace `z.unknown()` with an explicit `z.union` of the documented JSON types so the rendered schema instructs clients to send real typed values. No caller-contract change. Adds round-trip coverage for string/boolean/array/object in the set handler. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
setoperation'svalueinput is typedz.unknown(), so the rendered JSON Schema for the field carries notype. MCP clients that infer wire serialization from the schema (Claude Code does) then transmit non-string values as their JSON-string form; the handlerJSON.stringifys again before PATCHing, producing a double-encoded result:42→ stored as"42"(type lost)["a","b"]→ stored as the string'["a","b"]'This is the unresolved tail of #20 / #21 / #54. Those closed cleanly for the unit suite — but the unit tests call
input.parse()with native JS values, which bypasses the client transport where the mis-serialization actually happens, so they structurally can't catch it.Verification
Reproduced and fixed end-to-end against a live Obsidian Local REST API using the Claude Code MCP client (server v3.1.5, Windows 11). Pre-fix:
42→"42",["alpha","beta"]→'["alpha","beta"]'. Post-fix: number→42, array→a real YAML list, boolean→true, string→clean.Fix
Replace
z.unknown()with an explicitz.unionof the documented JSON types, so the rendered schema instructs clients to send real typed values rather than pre-stringified strings. No caller-contract change, and the existing native-value tests stay green.(#54 proposed
z.string()+ server-sideJSON.parse; the union achieves the same correctness without changing the caller contract.)Adds round-trip coverage in the
sethandler for string / boolean / array / object values.