{"slug": "i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server", "title": "I built an hourly newspaper for e-ink (and turned the pipeline into an MCP server)", "summary": "A developer built an hourly e-ink newspaper pipeline that pulls roughly 120 items from about 100 RSS feeds, uses Claude Haiku 4.5 on Bedrock as an automated editor, and typesets a 480x800 one-bit page for the Xteink X4 e-ink reader. The same pipeline now also generates a multi-page PDF for reMarkable and Kindle, a TRMNL plugin, and an MCP server that agents can call. The developer reports that listing the MCP server in registries drew scanners and health checks rather than humans, with \"Thirteen MCP calls, zero humans.", "body_md": "Every hour, a Lambda pulls about 120 items from ~100 RSS feeds, asks a small model to act as an editor, and typesets the result as a 480x800 one-bit page for the Xteink X4 e-ink reader on my desk. The same pipeline now produces a multi-page \"Morning Paper\" PDF for reMarkable and Kindle, a TRMNL plugin, and an MCP server that agents can call. This is what it does, what broke, and what I learned about \"news for agents\". Everything below is live at [https://briefing-service.wholemind.workers.dev](https://briefing-service.wholemind.workers.dev).\n\n## \n  \n  \n  The pipeline\n\n1. \n**Collect.** feedparser over ~100 feeds per briefing (AI, world, US, finance, sports, soccer, frontier-lab blogs). Each item keeps id, source, title, link, canonical link (utm and friends stripped), published, a 320-char summary, and a per-feed weight.\n2. \n**Dedupe.** Exact duplicates collapse by canonical URL. My first near-duplicate rule (title+summary word-shingle Jaccard >= 0.5) measured zero merges on 480 live candidates, and only five false pairs even at 0.2: outlets rewrite wire copy, and RSS summaries share boilerplate, not story text. What works is headline entity overlap: adjacent capitalised words form one entity (\"Wall Street\", \"Joao Pedro\"), punctuation and hyphens end a phrase, Title-Case outlets are filtered against their own summary, and two headlines from different outlets merge on three shared entities or two non-generic ones. On the same 429 news items that gives nine merges, all the same story on inspection. The survivor lists the other outlets in`also_in` ; the collapsed records are published too, with`duplicate_of` , the rule and a score, so anyone doing provenance work can audit the merges.\n3. \n**Rank.** Claude Haiku 4.5 on Bedrock gets the candidate list (id, source, age, title, summary) and a persona, and must call a`publish_briefing` tool with a lead, N stories, a research section, one-sentence summaries, a three-to-five-sentence detail passage, a why-it-matters line and key points. Facts must come from candidate text; the tool schema is the guardrail. A non-LLM fallback ranker (weight, recency, two-per-outlet cap) runs if the model call fails, so the device never shows a blank page.\n4. \n**Render.** Pillow draws a masthead, lead, numbered stories and a research strip into 480x800, dithers to 1-bit, writes BMPs the reader's firmware can page through, plus a wide 800x480 variant for TRMNL-class panels and a PDF for e-readers.\n5. \n**Publish.** S3 + CloudFront, a tiny manifest with a stamp that changes only when the editor's picks change, so the device never re-downloads unchanged pages.\n\n## \n  \n  \n  What surprised me\n\n- \n**The editor is the product.** The rendering is fun, but the thing people react to is \"lead + why it matters\" over a hundred sources with duplicates merged. That is why I exposed it as an API and an MCP server rather than keeping it a device toy.\n- \n**Agents are terrible customers so far.** Listing the MCP server in the official registry, Glama, Smithery and a few awesome-lists produced steady traffic in a day: scanners, auditors, and health checks. Thirteen MCP calls, zero humans. If you are building \"for agents\", expect the first wave to be bots evaluating you.\n- \n**E-ink people want files, not APIs.** reMarkable and Kindle owners asked for a PDF in their library each morning, so that exists (rmapi push, Send-to-Kindle email), free for the first ten.\n\n## \n  \n  \n  Try it\n\nI would like to hear what a \"news\" tool should return to your agent: full JSON, a short digest, or the rendered page.", "url": "https://wpnews.pro/news/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server", "canonical_source": "https://dev.to/jshelley/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server-1ebg", "published_at": "2026-09-12 22:54:03+00:00", "updated_at": "2026-09-12 23:25:00.528932+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "large-language-models", "generative-ai", "developer-tools"], "entities": ["Claude Haiku 4.5", "Amazon Bedrock", "Xteink X4", "reMarkable", "Kindle", "TRMNL", "MCP", "CloudFront"], "alternates": {"html": "https://wpnews.pro/news/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server", "markdown": "https://wpnews.pro/news/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server.md", "text": "https://wpnews.pro/news/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server.txt", "jsonld": "https://wpnews.pro/news/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server.jsonld"}}