fix(pdf-server): radio + dropdown in fill_form/save#577
Draft
fix(pdf-server): radio + dropdown in fill_form/save#577
Conversation
interact's get_screenshot/get_text waited the full 45s for a viewer that never mounted (host went idle before iframe reached startPolling), then timed out with a generic message. Now tracks viewsPolled and fails in ~8s with a recovery hint. Batch errors were also ordered success-first — hosts that flatten isError to content[0] showed "Queued: Filled N fields" and dropped the actual failure entirely. Viewer side: poll even when PDF load throws, and catch connect() rejection instead of silently blanking.
Three related bugs around non-text form fields:
Viewer fill_form (mcp-app.ts): writing a string to annotationStorage on
every radio widget trips pdf.js's inverted string coercion
(`value !== buttonValue` → true) — the first-rendered widget checks
itself and clears the rest, so whatever you ask for, you get the first
option. Fix: extract a setFieldInStorage() helper that writes
{value: true} only on the widget whose buttonValue matches, {value: false}
on siblings, matching pdf.js's own change handler. Also covers the
syncFormValuesToStorage() path (localStorage restore).
Save (pdf-annotations.ts): buildAnnotatedPdfBytes only knew about
getTextField/getCheckBox — dropdowns and radios threw in the try block
and fell through the catch, so they were silently dropped on save.
Fix: instanceof dispatch on getFieldMaybe(). For radios, accept either
the option label or a numeric buttonValue (indexed into getOptions()),
since the viewer stores the latter for PDFs with /Opt.
display_pdf output (server.ts): radio groups showed as N identical
`name [Btn]` lines with no way to tell them apart; dropdowns didn't
list their options. Fix: surface buttonValue as exportValue and the
options array from the annotation data already in hand.
@modelcontextprotocol/ext-apps
@modelcontextprotocol/server-basic-preact
@modelcontextprotocol/server-basic-react
@modelcontextprotocol/server-basic-solid
@modelcontextprotocol/server-basic-svelte
@modelcontextprotocol/server-basic-vanillajs
@modelcontextprotocol/server-basic-vue
@modelcontextprotocol/server-budget-allocator
@modelcontextprotocol/server-cohort-heatmap
@modelcontextprotocol/server-customer-segmentation
@modelcontextprotocol/server-debug
@modelcontextprotocol/server-map
@modelcontextprotocol/server-pdf
@modelcontextprotocol/server-scenario-modeler
@modelcontextprotocol/server-shadertoy
@modelcontextprotocol/server-sheet-music
@modelcontextprotocol/server-system-monitor
@modelcontextprotocol/server-threejs
@modelcontextprotocol/server-transcript
@modelcontextprotocol/server-video-resource
@modelcontextprotocol/server-wiki-explorer
commit: |
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
fill_form(mcp-app.ts): radio buttons always selected the first option regardless of the requested value. pdf.js'sRadioButtonWidgetAnnotation.render()coerces string storage values viavalue !== buttonValue— writing"medium"on every widget makes the first non-matching one check itself and clear siblings. NewsetFieldInStorage()writes{value: true}only on the matching widget, mirroring pdf.js's own change handler. Also covers the localStorage restore path (syncFormValuesToStorage).pdf-annotations.ts): dropdowns and radios were silently dropped —getTextField(name)throws for them and the catch swallowed it. Now dispatches ongetFieldMaybe() instanceof …. Radio values are accepted as either option label or numeric buttonValue (viewer stores the latter for PDFs with/Opt).display_pdfresult (server.ts): radio groups now showname=<exportValue> [Btn]per widget and dropdowns listoptions:[…]— previously the model had nothing to go on.Test plan
pdf-annotations.test.tscovering text/checkbox/dropdown/radio round-trip, numeric buttonValue → label indexing, invalid value, unknown field name. 153 pass / 0 fail.npm run --workspace examples/pdf-server buildcleansize: '2'selects Large,color: 'Green'selects Green,display_pdfshowssize=0/size=1/size=2 [Btn]andcolor [Ch] options:[Red, Green, Blue]