Skip to content

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 #4673

Description

@jeius

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions