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

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

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

  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.

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.

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.