MCPG Config
All templates

Web Reader

beta

Developer tools

Agents are bad at reading HTML and worse at reading PDFs, and the usual fix — paste the page in — spends thousands of tokens on navigation chrome. This template converts a page or a document to clean Markdown server-side, and hands back only the text.

A URL and an uploaded file both converging on one Markdown conversion step
Two entrances, one converter, and no HTML in the context window.

What you get

Two tools over one converter.

  • **web.read** — fetch one URL and return it as Markdown: headings, lists, tables and links kept; scripts, styling and navigation dropped. The response carries YAML front matter naming the source, so a model quoting the page can cite where the text came from.
  • **doc.read** — convert a document already held by the gateway's content store: PDF, Word, spreadsheet, archive. Pass the mcpg-resource:// URI the upload returned. The bytes are read server-side and never travel through the conversation.

The security posture is the point of the template, not a footnote:

  • **web.read fetches only allow-listed hosts.** A tool that fetches a caller-supplied URL is a request your gateway makes, from inside your network, on somebody else's instruction. The allow-list is what stops that being a problem, and it starts with exactly one host.
  • Private and link-local addresses are refused even for an allow-listed host, which is what closes 169.254.169.254 and the rest of the metadata surface.
  • Everything is size-capped: input, output, decompressed bytes, nesting depth, embedded documents, table rows and wall-clock time. A zip bomb trips the expansion ceiling rather than the input one.

What you need

  • A host worth reading, in the Host the reader may fetch field. One hostname, and only that hostname, becomes reachable through web.read.
  • An OpenID Connect provider, for the Identity provider issuer, Token audience and JWKS endpoint fields.

That is all. There are no secrets in this template and no upstream account to create — which also means nothing to rotate and nothing to leak.

To allow a second host, add it to the list after you download or publish:

yaml
url:
  allow_hosts: ["docs.example.com", "status.example.com"]

An empty list means any host that passes the address guard. That is a real configuration, and it is the wrong one for a gateway your agents can reach.

How it works

Both tools are dev.mcpg.backend.markdown bindings, differing only in which input modes they enable. web.read sets sources.url: true and leaves inline and resource off; doc.read does the opposite. A binding that enables url without the network_outbound capability grant is refused at boot rather than quietly failing to fetch — the grant in plugins[] is load-bearing.

The converter parses the document into blocks and renders those blocks as Markdown, rather than running a regex over HTML. That is why a table survives as a table and a code block survives as a code block. preserve_unsupported_html is off, so anything the parser cannot model is dropped with a warning instead of being passed through as raw markup a model then has to ignore.

The two bindings carry different limits on purpose. web.read caps output at 1 MiB and finishes in 30 seconds, because a page that needs more than that is a page an agent should not be reading whole. doc.read allows 4 MiB and a minute, because a real PDF earns it.

The first five minutes after it boots

  1. Call web.read on a page on your allow-listed host. Check the front matter at the top names the URL you asked for.
  2. Call web.read on a host that is not allow-listed. It should be refused. If it is not, the allow-list did not render — check the config.
  3. Call web.read on http://169.254.169.254/. It should be refused twice over: wrong host, private address.
  4. Upload a PDF through your client and call doc.read with the returned mcpg-resource:// URI. Confirm the headings survived.
  5. Try a large document and watch it truncate at a block boundary rather than mid-sentence — that is max_output_bytes doing its job.

Notes

  • **dev.mcpg.backend.markdown is not baked into the published gateway images.** It is pulled from ghcr.io/mcpg-dev/plugins/backend-markdown at boot, so the host needs registry access on first start, or a configured mirror.
  • **doc.read needs a content store with something in it.** The gateway creates an in-process store by default, which is enough to try the tool but is lost on restart. Point storage.providers at a filesystem or S3 provider before you rely on it.
  • The allow-list is per binding, not per gateway. If you add a third tool later, it gets its own list. That is deliberate: one tool that may reach a vendor's docs should not implicitly let another reach them too.
  • This template has no upstream credential, so there is no cred:// reference and no credential issuer in a cloud publish. It is the simplest thing in the gallery to get running, and a reasonable first thing to try.
Web Reader · MCPG Config