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

Open
#762 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
65/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
typescript
Domain
api

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.

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

  1. Run the server: npx @modelcontextprotocol/server-pdf --stdio <allowed-dir>
  2. Send an initialize handshake, then:
    {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"read_pdf_bytes","arguments":{"url":"/path/to/file.pdf","offset":0,"byteCount":256}}}
    
  3. Raw server response (verified by talking to the stdio transport directly):
    {
      "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
      }
    }
    
    The base64 bytes decode to the real %PDF-1.4 header, 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-pdf 2.0.0 (installed via npx, run with --stdio under Docker isolation)
  • Client: opencode CLI (terminal MCP client)
  • The server runs fine: connection, init, and tool discovery all succeed; only content delivery is affected.
Dominant language
TypeScript
Stars
2.9k
Forks
387
Avg merge
3h 21m
Merged PRs (30d)
6

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from modelcontextprotocol/ext-apps

All issues in modelcontextprotocol/ext-apps

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.