<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jordan Shelley</title>
    <description>The latest articles on DEV Community by Jordan Shelley (@jshelley).</description>
    <link>https://dev.to/jshelley</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4122649%2F6d0541a7-a6bb-4317-9316-85877d638f8e.jpg</url>
      <title>DEV Community: Jordan Shelley</title>
      <link>https://dev.to/jshelley</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jshelley"/>
    <language>en</language>
    <item>
      <title>I built an hourly newspaper for e-ink (and turned the pipeline into an MCP server)</title>
      <dc:creator>Jordan Shelley</dc:creator>
      <pubDate>Sat, 12 Sep 2026 22:54:03 +0000</pubDate>
      <link>https://dev.to/jshelley/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server-1ebg</link>
      <guid>https://dev.to/jshelley/i-built-an-hourly-newspaper-for-e-ink-and-turned-the-pipeline-into-an-mcp-server-1ebg</guid>
      <description>&lt;p&gt;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 &lt;a href="https://briefing-service.wholemind.workers.dev" rel="noopener noreferrer"&gt;https://briefing-service.wholemind.workers.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Collect.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedupe.&lt;/strong&gt; Exact duplicates collapse by canonical URL. My first near-duplicate rule (title+summary word-shingle Jaccard &amp;gt;= 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 &lt;code&gt;also_in&lt;/code&gt;; the collapsed records are published too, with &lt;code&gt;duplicate_of&lt;/code&gt;, the rule and a score, so anyone doing provenance work can audit the merges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rank.&lt;/strong&gt; Claude Haiku 4.5 on Bedrock gets the candidate list (id, source, age, title, summary) and a persona, and must call a &lt;code&gt;publish_briefing&lt;/code&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The editor is the product.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents are terrible customers so far.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-ink people want files, not APIs.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Read: the front pages and JSON are free, 25 API/MCP calls per IP per day: &lt;a href="https://briefing-service.wholemind.workers.dev" rel="noopener noreferrer"&gt;https://briefing-service.wholemind.workers.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Provenance work: &lt;a href="https://briefing-service.wholemind.workers.dev/v1/briefings/ai/candidates" rel="noopener noreferrer"&gt;https://briefing-service.wholemind.workers.dev/v1/briefings/ai/candidates&lt;/a&gt; is the full hourly candidate set, free, no key.&lt;/li&gt;
&lt;li&gt;Agents: MCP endpoint at &lt;a href="https://briefing-service.wholemind.workers.dev/mcp" rel="noopener noreferrer"&gt;https://briefing-service.wholemind.workers.dev/mcp&lt;/a&gt; (streamable HTTP), tools &lt;code&gt;list_briefings&lt;/code&gt;, &lt;code&gt;get_briefing&lt;/code&gt;, &lt;code&gt;get_page&lt;/code&gt;, &lt;code&gt;render_briefing&lt;/code&gt;. Installable: &lt;code&gt;npx -y github:jshelley/briefing-mcp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paid: $9/month Reader key, x402 per call (USDC on Base), $49/month Team Briefing over your own feeds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would like to hear what a "news" tool should return to your agent: full JSON, a short digest, or the rendered page.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>mcp</category>
      <category>eink</category>
    </item>
  </channel>
</rss>
