modelcontextprotocol / modelcontextprotocol/ext-apps
server-pdf: read_pdf_bytes hides the byte payload in structuredContent only — text content is a bare size summary, so CLI clients can't read the PDF
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 387
- Avg merge
- 3h 21m
- Merged PRs (30d)
- 6
Description
Summary
@modelcontextprotocol/server-pdf v2.0.0's read_pdf_bytes returns the requested bytes only inside structuredContent. The content[0].text block contains just a size summary like 256 bytes at 0/641720 with no data.
Clients that render only content[] text blocks (e.g. terminal/CLI MCP clients like opencode) never see the bytes — they are silently dropped. The description also warns "The model should NOT call this tool directly", yet it is the only server-side way to get raw PDF content when the interactive viewer path is unavailable.
Reproduction
- Run the server:
npx @modelcontextprotocol/server-pdf --stdio <allowed-dir> - Send an
initializehandshake, then:{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"read_pdf_bytes","arguments":{"url":"/path/to/file.pdf","offset":0,"byteCount":256}}} - Raw server response (verified by talking to the stdio transport directly):
The base64{ "content": [{"type": "text", "text": "256 bytes at 0/641720"}], "structuredContent": { "url": "/path/to/file.pdf", "bytes": "JVBERi0xLjQ...", "offset": 0, "byteCount": 256, "totalBytes": 641720, "hasMore": true } }bytesdecode to the real%PDF-1.4header, so the data is correct — it's just unreachable to text-only clients.
Expected behavior
The byte payload should be reachable through the standard content[] text block, e.g. include the JSON payload (or the base64 bytes) in the text content, not only in structuredContent. Any MCP client that renders content[] should be able to consume the data without requiring structured-content support.
Related issue: display_pdf + interact requires an interactive viewer
display_pdf returns a viewUUID and interact get_text waits for the viewer iframe to poll within 8 seconds ("Viewer never connected for viewUUID ... (no poll within 8s)"). In headless/CLI contexts no iframe mounts, so text extraction via this path always fails. There is no non-viewer server-side text-extraction tool, so headless clients have no working path to PDF text today.
Environment
- Package:
@modelcontextprotocol/server-pdf2.0.0 (installed via npx, run with--stdiounder Docker isolation) - Client: opencode CLI (terminal MCP client)
- The server runs fine: connection, init, and tool discovery all succeed; only content delivery is affected.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the server-pdf read_pdf_bytes tool entry point and trace how its response builds content[] and structuredContent. Reproduce the stdio call with a small byte range, then verify that the returned content[] text exposes the payload for text-only clients while preserving the existing byte metadata and data.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100