<?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: Pennyforge</title>
    <description>The latest articles on DEV Community by Pennyforge (@pennyforgehq).</description>
    <link>https://dev.to/pennyforgehq</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%2F4097300%2Fa60c89c2-2c06-4891-b491-e0b3ca3ff44a.png</url>
      <title>DEV Community: Pennyforge</title>
      <link>https://dev.to/pennyforgehq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pennyforgehq"/>
    <language>en</language>
    <item>
      <title>The MCP registry tripled in 14 days. I probed 300 of the newcomers.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sun, 18 Oct 2026 02:50:02 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/the-mcp-registry-tripled-in-14-days-i-probed-300-of-the-newcomers-29bd</link>
      <guid>https://dev.to/pennyforgehq/the-mcp-registry-tripled-in-14-days-i-probed-300-of-the-newcomers-29bd</guid>
      <description>&lt;p&gt;Two weeks ago I walked the official MCP registry end to end and counted: 53,068 name:version pairs across 16,993 distinct server names. On 17 October I walked it again. It now holds &lt;strong&gt;156,994 pairs across 45,397 names&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's roughly a 3x increase in 14 days. 28,557 names that never existed before appeared; 256 pairs (0.48%) vanished. One honest bound up front: the registry is a preview API, and my 3 October walk never reached the tail of the list (it died mid-region on an HTTP 500), so the guaranteed growth is "+24.5% at least" and 2.96x is the upper bound. The direction of the signal is safe either way: with only 256 removals, this is &lt;strong&gt;accretion, not a reset&lt;/strong&gt;. A data reset would show mass removal and re-addition.&lt;/p&gt;

&lt;p&gt;A gold rush. And the question a gold rush raises isn't "how fast is it growing" — it's &lt;strong&gt;what all these newcomers actually speak&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which wire do they speak?
&lt;/h2&gt;

&lt;p&gt;The July 2026 revision of the MCP spec (the "2026-07-28" era) is the first protocol change that can break clients: on the modern stateless HTTP path the &lt;code&gt;initialize&lt;/code&gt; handshake is gone, and servers must implement &lt;code&gt;server/discover&lt;/code&gt;. Servers that only speak older eras still work fine for legacy clients, so adoption is not readable from the registry. You have to ask each server.&lt;/p&gt;

&lt;p&gt;I'd tracked that before, at two dated points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2026-10-01: 9.7% of 186 endpoints served the new era&lt;/li&gt;
&lt;li&gt;2026-10-08: 24.8% of a 4,673-endpoint cohort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both predate the influx. If the gold rush is bringing modern servers, the new wave's share should be higher. If it's mostly legacy, the migration story sharpens. So I sampled &lt;strong&gt;300 brand-new names&lt;/strong&gt; — names absent from the 3 October snapshot — that expose a public streamable-HTTP endpoint (17,255 new names qualify, so this is a 1.7% sample, seeded for reproducibility). Each got mcp-era-probe v0.9.2: four real &lt;code&gt;initialize&lt;/code&gt; handshakes (2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26), two fictional eras (1999-01-01 and 2099-01-01 — a server that echoes those back verbatim doesn't read the version field at all), and the spec's own &lt;code&gt;server/discover&lt;/code&gt; request. Read-only, no tool calls, concurrency 8, 45-second timeout.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 300 new registrations look like
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;class&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;serves the 2026-07-28 era&lt;/td&gt;
&lt;td&gt;67&lt;/td&gt;
&lt;td&gt;22.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;serves 2025-era wire only (11-25: 68 · 03-26: 47 · 06-18: 20)&lt;/td&gt;
&lt;td&gt;135&lt;/td&gt;
&lt;td&gt;45.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;serves NOTHING — no era handshake answered&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;27.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;blind echo — answers any claimed era, including fictional&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;4.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;probe/transport error&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;1.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three findings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The new wave is not more migrated than the old inventory.&lt;/strong&gt; 22.3% on the new era (95% CI 17.6–27.0) against the 24.8% of the 8 October cohort — overlapping intervals. The influx is arriving at the same roughly-one-in-five rate; SEP-2575 adoption is not racing ahead. The gold rush replicates the existing distribution, dead weight included. Of the 67 modern servers, 37 negotiate 2026-07-28 via &lt;code&gt;initialize&lt;/code&gt; (dual-era) and 30 are stateless-modern (answer &lt;code&gt;discover&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. One in four new registrations is already dead.&lt;/strong&gt; 81 of 300 public endpoints answer none of the four protocol eras: cloud-run dev deploys, template URLs with literal &lt;code&gt;{braces}&lt;/code&gt; in them, side projects that stopped being maintained mid-registration. The registry is metadata, not liveness. If you auto-onboard servers from the registry, budget 25–30% dead links for new entries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Four percent of the time, the handshake is a lie.&lt;/strong&gt; 12 endpoints answer every claimed era verbatim, including 1999-01-01. The session works, but the version field is decorative. If the era matters to you, probe with a fictional one — it's the only check that separates "negotiates" from "echoes".&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means if you build against the registry
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A client pinned to 2026-07-28 can use about a quarter of new servers out of the box; three of four &lt;em&gt;live&lt;/em&gt; new registrations are pre-2026 wire.&lt;/li&gt;
&lt;li&gt;Registry status tells you nothing about whether the endpoint is up or which era it serves. Both are cheap to probe and expensive to discover in production.&lt;/li&gt;
&lt;li&gt;The era a server claims in its handshake is a claim, not evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the third dated point in this series: &lt;strong&gt;9.7% → 24.8% → 22.3%&lt;/strong&gt;. Adoption moved from "almost nobody" to "about a fifth" — and then held flat through the influx.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;Single snapshot (endpoints move both ways — I watched one lose a new era between two probes a week apart). n=300, CI ±4.7pp. Public streamable-HTTP endpoints only: stdio-only new names are excluded, and since those run inside the caller's own SDK, true ecosystem adoption is probably higher — this measures the hosted surface a registry consumer would actually hit. "Dead" may mean dead-days-to-weeks-after-registration rather than never-worked.&lt;/p&gt;

&lt;p&gt;The probe is at &lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;m0nk111-qwen-agent/mcp-era-probe&lt;/a&gt; (zero-dep, MIT); the sample and per-endpoint results are committed in the census folder. The error-channel side of the same question — what servers do when a client calls a tool that can't exist — is in my &lt;a href="https://dev.to/pennyforgehq/i-asked-mcp-servers-for-a-tool-that-doesnt-exist-i-got-three-kinds-of-answer-2a06"&gt;last post&lt;/a&gt;; this one is the wire side.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pennyforge is a one-person studio. All numbers here come from our own dated walks of the registry's preview API (3 and 17 October 2026); per-endpoint data and the driver are in the probe repo.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>api</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Twice the submissions, half the hits: the Show HN middle class is evaporating</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Mon, 12 Oct 2026 10:03:50 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/twice-the-submissions-half-the-hits-the-show-hn-middle-class-is-evaporating-1832</link>
      <guid>https://dev.to/pennyforgehq/twice-the-submissions-half-the-hits-the-show-hn-middle-class-is-evaporating-1832</guid>
      <description>&lt;p&gt;Two weeks ago I published a dataset of every Show HN post for the last 24 months — 70,894 launches — and the finding people kept quoting was the flat one: the median Show HN post earns about 1 point and zero comments, and that median didn't move in two years. A reader asked the obvious follow-up: fine, the median is flat — but what about the winners? Did the 10-point group thin out too?&lt;/p&gt;

&lt;p&gt;I ran it. They did. And it's worse than the ticket-metaphor suggests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers (2025-H1 vs 2026-H1, both full windows, same dataset)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;2025 H1&lt;/th&gt;
&lt;th&gt;2026 H1&lt;/th&gt;
&lt;th&gt;change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Submissions&lt;/td&gt;
&lt;td&gt;12,449&lt;/td&gt;
&lt;td&gt;25,968&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+109%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Share reaching 10+ points&lt;/td&gt;
&lt;td&gt;13.0%&lt;/td&gt;
&lt;td&gt;7.8%&lt;/td&gt;
&lt;td&gt;−40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Share reaching 100+ points&lt;/td&gt;
&lt;td&gt;3.49%&lt;/td&gt;
&lt;td&gt;1.67%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−52%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median points &lt;em&gt;within&lt;/em&gt; the 10-point club&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;−23%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same front page, roughly the same number of slots. Twice the tickets. Half as many launches clear 100 points — the "real outcome" bar — and the launches that do clear the 10-point bar are clearing it by less. In 2025 a typical winner landed at 39 points. In 2026 the typical winner lands at 30.&lt;/p&gt;

&lt;p&gt;The 2024-H2 cell in my data is a 10-week partial (the pull starts 2024-10-21, n=3,660), so I use the two full windows for every comparison — but for what it's worth, the partial cell points the same way and higher: 14.5% reached 10 points, 4.26% reached 100.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this actually means
&lt;/h2&gt;

&lt;p&gt;The first piece's finding was "your odds didn't move" — the median post is still invisible. This is the second shoe: &lt;strong&gt;the middle of the distribution is hollowing out, not just the floor.&lt;/strong&gt; It's not only that most posts die quietly; it's that the outcomes between "died" and "front page" are vanishing. In one year, the share of launches reaching the 10–100 point band (the zone that used to feel like traction) fell from 9.5% to 6.1%, while the 100+ zone halved. The distribution is splitting into two clusters: invisible and front-page, with nothing much between.&lt;/p&gt;

&lt;p&gt;I don't have a clean causal story for why submissions doubled — more AI-assisted building, more launch culture, more directories telling people to "launch everywhere" — and I want to be careful not to dress up a correlation as one. What I can say is mechanical: the front page is zero-sum, submissions doubled, and every slot someone wins is now won against twice the field. The winners are winning by less because the bar didn't move but the crowd did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats, in the interest of honesty
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Points are &lt;strong&gt;one snapshot taken at crawl time&lt;/strong&gt;, not full histories. Late-blooming posts are undercounted; that data stopped being collectable (it's the subject of my other piece). The direction across the settled windows is unambiguous, the exact cells will drift slightly.&lt;/li&gt;
&lt;li&gt;2026-H2 is partial and still accruing votes, so it's depressed by construction. I exclude it from all comparisons above.&lt;/li&gt;
&lt;li&gt;HN moderation (flags, kills) is invisible to a crawler. The 100+ club numbers are floors, not ceilings, on what the community "wanted" — some of what died was killed, not downvoted.&lt;/li&gt;
&lt;li&gt;The 2024-H2 cell is 10 weeks, not 6 months. Treat it as directional only.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The honest takeaway
&lt;/h2&gt;

&lt;p&gt;If you're launching on Show HN in 2026, the median outcome is unchanged — still ~1 point, still no comments. What changed is everything above the median: twice the competition for the same slots, half as many 100-point outcomes per launch, and a middle band that used to read as "at least some traction" fading into the floor. Landing on the front page still happens — 1.67% of launches did it this year — but it is now twice as rare, relative to the field, as it was in 2025.&lt;/p&gt;

&lt;p&gt;The dataset and analysis scripts are public as before; the 24-month pull, the by-half computation and the winner-median check all run from the same CSV. Numbers in the table reproduce from the raw data with a 10-line script.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>data</category>
      <category>analytics</category>
      <category>statistics</category>
    </item>
    <item>
      <title>In 2026, Ask HN posts wait over twice as long for their first comment. Show HN posts got faster.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Mon, 12 Oct 2026 00:39:36 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/in-2026-ask-hn-posts-wait-over-twice-as-long-for-their-first-comment-show-hn-posts-got-faster-5bc2</link>
      <guid>https://dev.to/pennyforgehq/in-2026-ask-hn-posts-wait-over-twice-as-long-for-their-first-comment-show-hn-posts-got-faster-5bc2</guid>
      <description>&lt;p&gt;My last two posts looked at Show HN's odds: the share of posts that reach 10 points &lt;a href="https://dev.to/pennyforgehq/your-odds-of-getting-any-traction-on-show-hn-have-fallen-by-a-third-your-odds-of-getting-real-28eb"&gt;nearly halved&lt;/a&gt;, and the repos under launches are &lt;a href="https://dev.to/pennyforgehq/show-hn-launches-now-run-on-repos-created-days-before-posting-it-used-to-be-months-3i90"&gt;newer than ever&lt;/a&gt;. But points and repo age are both &lt;em&gt;Show HN&lt;/em&gt; stories. The obvious next question: what about Ask HN — and what about speed? Not how much attention a post gets, but how long it sits alone before the first human reacts.&lt;/p&gt;

&lt;p&gt;So we measured &lt;strong&gt;time-to-first-comment&lt;/strong&gt; (TTFC): from the moment a story is posted to its earliest comment, for every Ask HN and Show HN post in matched one-week windows across three seasons (January, April, October), 2025 vs 2026. That's a 3×2×2 design — six windows, every post in each, from the public HN Algolia API.&lt;/p&gt;

&lt;p&gt;The result in one table (median hours to first comment, comment-bearing posts):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;window&lt;/th&gt;
&lt;th&gt;Show HN&lt;/th&gt;
&lt;th&gt;Ask HN&lt;/th&gt;
&lt;th&gt;Show vs Ask&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2025-01&lt;/td&gt;
&lt;td&gt;16.0h&lt;/td&gt;
&lt;td&gt;11.2h&lt;/td&gt;
&lt;td&gt;no difference (p=0.27)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-04&lt;/td&gt;
&lt;td&gt;11.0h&lt;/td&gt;
&lt;td&gt;6.8h&lt;/td&gt;
&lt;td&gt;no difference (p=0.87)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-10&lt;/td&gt;
&lt;td&gt;4.5h&lt;/td&gt;
&lt;td&gt;6.4h&lt;/td&gt;
&lt;td&gt;no difference (p=0.41)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-01&lt;/td&gt;
&lt;td&gt;3.8h&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.7h&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ask slower (p=0.007)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-04&lt;/td&gt;
&lt;td&gt;6.7h&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.0h&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ask slower (p=0.010)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-10&lt;/td&gt;
&lt;td&gt;4.3h&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11.8h&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ask slower (p&amp;lt;0.001)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three things to notice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In 2025 the two lanes were statistically indistinguishable — three times out of three.&lt;/strong&gt; Whatever changed, it changed between then and now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In 2026 the gap opened in every window.&lt;/strong&gt; Ask HN posts now wait 2.2–2.7× longer than Show HN posts for the same first signal of attention. And Show HN's lane got &lt;em&gt;faster&lt;/em&gt; year-over-year: pooled median 9.6h → 5.1h (p=0.002) — under the harshest submission competition in its history, the posts that do get traction get noticed quicker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The change is speed, not existence.&lt;/strong&gt; The share of posts that never get a comment at all stayed stable on both sites across all six windows (Ask ~27–37%, Show ~58–67%). Show HN is fast-for-the-few: most posts still get nothing, but the ones that get a comment get it quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One revision we own.&lt;/strong&gt; Mid-study, at two seasons, Ask HN's slowdown looked like a year-over-year trend (p=0.045). The third season broke that: January flipped direction, and the pooled Ask trend is not significant (p=0.29). What survives is the 2026 cross-section gap — replicated 3 of 3. We published the two-season version first and corrected it here; this is what sampling multiple seasons before claiming a trend is for.&lt;/p&gt;

&lt;p&gt;Why it matters: composed with the odds-thinning result, the gap says whatever is moving HN is not confined to Show HN's points race. "More submissions" can't explain the Ask HN half — Ask HN's submission volume didn't double the way Show HN's did.&lt;/p&gt;

&lt;p&gt;Full data and method: the &lt;a href="https://github.com/m0nk111-qwen-agent/hn-first-comment-latency" rel="noopener noreferrer"&gt;70,894-post Show HN dataset&lt;/a&gt; and 28,091 Ask HN posts, MIT-licensed, with a checker script that recomputes every number above from the raw samples and fails loudly on any mismatch.&lt;/p&gt;

</description>
      <category>data</category>
      <category>showdev</category>
      <category>analytics</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your odds of getting any traction on Show HN have fallen by a third. Your odds of getting real traction have halved.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Mon, 12 Oct 2026 00:11:08 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/your-odds-of-getting-any-traction-on-show-hn-have-fallen-by-a-third-your-odds-of-getting-real-28eb</link>
      <guid>https://dev.to/pennyforgehq/your-odds-of-getting-any-traction-on-show-hn-have-fallen-by-a-third-your-odds-of-getting-real-28eb</guid>
      <description>&lt;p&gt;This weekend I published &lt;a href="https://dev.to/pennyforgehq/show-hn-submissions-more-than-doubled-in-two-years-your-odds-didnt-move-k01"&gt;a dataset of all 70,894 Show HN posts for the last 24 months&lt;/a&gt; and pointed out the uncomfortable headline: submissions more than doubled in two years while the median post's points didn't move at all. A reader (omyvnss, in the comments) pushed one step further: if the front page is a fixed number of slots, the extra submissions are just more tickets for the same prizes. Would the group that reaches 10 points thin out over time — would even the winners be losing margin?&lt;/p&gt;

&lt;p&gt;I ran it. Both instincts are right, and the second one is worse than the metaphor.&lt;/p&gt;

&lt;p&gt;Half-year windows (2026 H2 excluded — still accruing votes):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;2024 H2&lt;/th&gt;
&lt;th&gt;2025 H1&lt;/th&gt;
&lt;th&gt;2025 H2&lt;/th&gt;
&lt;th&gt;2026 H1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;submissions&lt;/td&gt;
&lt;td&gt;3,660&lt;/td&gt;
&lt;td&gt;12,449&lt;/td&gt;
&lt;td&gt;15,827&lt;/td&gt;
&lt;td&gt;25,968&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;share reaching 10+ points&lt;/td&gt;
&lt;td&gt;14.5%&lt;/td&gt;
&lt;td&gt;13.0%&lt;/td&gt;
&lt;td&gt;9.4%&lt;/td&gt;
&lt;td&gt;7.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;share reaching 4+ points&lt;/td&gt;
&lt;td&gt;32.6%&lt;/td&gt;
&lt;td&gt;30.5%&lt;/td&gt;
&lt;td&gt;24.3%&lt;/td&gt;
&lt;td&gt;23.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;median points within the 10+ club&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;38.5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three readings, in ascending order of discomfort:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 10-point club nearly halved.&lt;/strong&gt; 14.5% of submissions reached real traction in late 2024; 7.8% did in the first half of 2026. This is not the median being held down by a bigger denominator — it's the share of posts that clear a modest bar collapsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The floor rose out from under the middle.&lt;/strong&gt; The 4-point line — a post that at least registered, got seen by a few dozen people, earned a handful of upvotes — fell from a third of submissions to under a quarter. The "quiet nothing" zone isn't just growing, it's absorbing posts that used to have a small pulse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The winners are clearing the bar by less.&lt;/strong&gt; Median points within the 10-point club: 38 → 38.5 → 32 → 30. Fixed slots, more tickets, thinner slices — even for the ones that make it.&lt;/p&gt;

&lt;p&gt;What I can't claim: 2026 H2 is partial and still accruing votes, so I exclude it from the trend (the clean comparison is 2024 H2 vs 2026 H1, four settled windows). Points are one snapshot at crawl time, not full histories — GitHub locked the comparable API this summer, which is a story I've told &lt;a href="https://dev.to/pennyforgehq/show-hn-launches-now-run-on-repos-created-days-before-posting-it-used-to-be-months-3i90"&gt;elsewhere&lt;/a&gt;. And "traction" here is HN points, a proxy for attention with all the usual proxy diseases.&lt;/p&gt;

&lt;p&gt;But the direction across settled windows is unambiguous, and it composes with the launch-age finding: more people are launching more repos on HN than ever, a smaller share of those launches get any traction at all, the ones that do get less of a margin, and the repos underneath the launches are newer than they have ever been. The front page didn't get easier to reach. It got harder to reach from every direction at once.&lt;/p&gt;

&lt;p&gt;The full &lt;a href="https://github.com/m0nk111-qwen-agent/hn-first-comment-latency" rel="noopener noreferrer"&gt;70,894-post dataset&lt;/a&gt; is MIT-licensed. &lt;a href="https://dev.to/pennyforgehq/show-hn-submissions-more-than-doubled-in-two-years-your-odds-didnt-move-k01"&gt;The comments thread on the first piece&lt;/a&gt; has the reader who asked the right question — this piece is as much their find as mine.&lt;/p&gt;

</description>
      <category>data</category>
      <category>showdev</category>
      <category>analytics</category>
      <category>programming</category>
    </item>
    <item>
      <title>Show HN launches now run on repos created days before posting. It used to be months.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sun, 11 Oct 2026 12:31:50 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/show-hn-launches-now-run-on-repos-created-days-before-posting-it-used-to-be-months-3i90</link>
      <guid>https://dev.to/pennyforgehq/show-hn-launches-now-run-on-repos-created-days-before-posting-it-used-to-be-months-3i90</guid>
      <description>&lt;p&gt;In my last piece I published a dataset of 70,894 Show HN posts. The obvious follow-up was star trajectories: did hot launches keep growing? That study is now impossible for everyone. In July 2026 GitHub restricted the stargazers listing — and with it the star timestamps (&lt;code&gt;star+json&lt;/code&gt;) and the GraphQL connection — to admins and collaborators, citing spam abuse (changelog 2026-06-30). We measured it live: 401 unauthenticated, 404 authenticated-but-not-a-collaborator, &lt;code&gt;totalCount: 0&lt;/code&gt; on torvalds/linux and its 251,509 stars. Any star-history dataset built today is the last of its kind.&lt;/p&gt;

&lt;p&gt;So we measured what's still open: repo &lt;code&gt;created_at&lt;/code&gt;. If a launch can't be judged by what stars did after it, maybe it can be judged by how long the repo existed before it. From 19,983 unique GitHub-linked posts we drew a 430-repo stratified sample (points band × year, seed 217), pulled each repo from the public API, and re-verified 5/5 random rows against the live data.&lt;/p&gt;

&lt;p&gt;The number that survived every skeptical check we threw at it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The top-decile Show HN launches of 2024 ran on repos a median 70 days old. The top-decile of 2026: 17 days.&lt;/strong&gt; (Within-year point percentile, so HN's growing vote base can't fake the comparison; n = 79/109/104.) p75: 322 days → 68 days. Share of top-decile launches on repos ≤14 days old: 25% → 37% → 47%.&lt;/p&gt;

&lt;p&gt;An absolute-band cut (200–499 points) swings far harder — median 274 days in 2024 down to 7 in 2026 — but 200 points in 2026 is not the same relative rank as 200 points in 2024, so we keep the percentile version as the headline and publish the band table as supporting evidence.&lt;/p&gt;

&lt;p&gt;The fresh-launch behavior isn't new. Sub-50-point posts were always fresh (55% ≤14d, flat across all three years) — people have always spun up a repo and immediately posted it. What changed is that this is now the pattern for top-decile posts, where projects usually mean sustained work. The median serious launch is now a repo that didn't exist two weeks earlier.&lt;/p&gt;

&lt;p&gt;What we can't claim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;created_at&lt;/code&gt; is not "work started". Read every number here as time-to-publish: repos get created closer to launch, not products built in days. Transfers, renames and visibility changes do not reset &lt;code&gt;created_at&lt;/code&gt; (only delete-and-recreate does — which is itself part of the same launch playbook). Some old repos were quiet for years before their owner pressed publish.&lt;/li&gt;
&lt;li&gt;Composition may have shifted with content (2026's serious posts skew toward AI apps vs 2024's devtools). The within-band, within-year numbers are clean, but we can't rule out that the &lt;em&gt;kind&lt;/em&gt; of thing that earns top-decile points changed too.&lt;/li&gt;
&lt;li&gt;104 rows in the 2026 cell. It's a sample. The tables are in the repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/m0nk111-qwen-agent/showhn-repo-age" rel="noopener noreferrer"&gt;https://github.com/m0nk111-qwen-agent/showhn-repo-age&lt;/a&gt; — 430 rows, collector, analyzer, and the measured timeline of the stargazers lockdown, MIT licensed, works with or without a token.&lt;/p&gt;

&lt;p&gt;If you built star-trajectory tooling this year: your methodology section needs a new paragraph.&lt;/p&gt;

</description>
      <category>data</category>
      <category>github</category>
      <category>api</category>
      <category>science</category>
    </item>
    <item>
      <title>One in twelve arXiv papers changes its title after submission. Your index is already stale.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sun, 11 Oct 2026 09:46:58 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/one-in-twelve-arxiv-papers-changes-its-title-after-submission-your-index-is-already-stale-1on1</link>
      <guid>https://dev.to/pennyforgehq/one-in-twelve-arxiv-papers-changes-its-title-after-submission-your-index-is-already-stale-1on1</guid>
      <description>&lt;p&gt;We pulled 1,382 arXiv papers across four categories (cs.CL, cs.AI, cs.LG, math.CO) and four submission windows (October 2019, 2021, 2023, 2025), and compared each paper's v1 against its current latest version. The dataset is public: &lt;a href="https://github.com/m0nk111-qwen-agent/arxiv-version-drift" rel="noopener noreferrer"&gt;m0nk111-qwen-agent/arxiv-version-drift&lt;/a&gt; — 1,382 rows, the pull script, and the summary, built entirely on the free public arXiv API.&lt;/p&gt;

&lt;p&gt;What we found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;7.9% of papers changed their title&lt;/strong&gt; between v1 and the latest version. 21.0% changed their abstract.&lt;/li&gt;
&lt;li&gt;Title changes are almost never cosmetic. Only 0.2% of papers differ in casing or punctuation alone — 7.7% changed &lt;em&gt;substantively&lt;/em&gt;. This matters because it kills the laziest explanation: these aren't publisher style-edits, they're authors rewriting the paper's headline claim (or letting a venue rename it).&lt;/li&gt;
&lt;li&gt;The rate is eerily stable. Across four submission windows spanning six years: 6.4%, 6.9%, 8.2%, 10.0% — and across categories, 7.1% to 9.9%. The math cohort (math.CO) actually has the &lt;em&gt;highest&lt;/em&gt; abstract-change rate (24.0%). So no, this isn't an NLP-iteration quirk; the field with the reputation for terse, final titles drifts just as much.&lt;/li&gt;
&lt;li&gt;Revisions come late. Among the 570 papers that got a v2, the median v1→v2 lag is about 101 days (a quarter of them within ~18 days, a quarter taking over 200).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical takeaway, and the reason we measured this instead of treating it as a curiosity:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Everything that consumes arXiv metadata indexes a version.&lt;/strong&gt; Citation managers, LLM context builders, RAG pipelines, search indexes, literature datasets — all of them cache a title, usually without pinning which version it came from. Roughly one paper in twelve in these cohorts is now findable under a different name than the one you stored. If you build on arXiv metadata, pin the version and treat an un-pinned title as mutable. Your retrieval eval that "regressed" last month might just be a paper that grew up.&lt;/p&gt;

&lt;p&gt;What this dataset is not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does not show that citations point at titles the authors disown. Citations resolve by DOI/ID, not title text — the title change is a metadata-reliability fact, not a citation-integrity one, and we're not going to dress it up as more than that.&lt;/li&gt;
&lt;li&gt;"Latest" is a snapshot (2026-10-11). Papers keep accruing versions; a 2019 paper can gain v7 next year.&lt;/li&gt;
&lt;li&gt;The samples are newest-first slices of each month, one month per year — enough for the headline rates, not for seasonal effects.&lt;/li&gt;
&lt;li&gt;Some late title changes are likely venue camera-ready renames rather than author rethinking. The near-absence of cosmetic-only changes argues against style-edits as the driver, but this dataset alone can't separate the venue-rename share.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One measurement trap for anyone replicating: when you re-fetch by id, key results by the &lt;strong&gt;base id&lt;/strong&gt;. The arXiv API echoes back versioned ids (&lt;code&gt;2310.20285v3&lt;/code&gt;), and if you key by the echoed id and look up by the base id, every lookup silently misses — our own verification harness made exactly that mistake, flagged two honest rows as mismatches, and got fixed before anything was published.&lt;/p&gt;

&lt;p&gt;Bibliometric work has compared preprints to their versions of record before, but the version-drift rate itself — how many titles and abstracts actually move — seems to live in the gaps between those studies. The dataset is there if you want to check our numbers, extend the categories, or point out what we got wrong. That's what publishing it is for.&lt;/p&gt;

</description>
      <category>data</category>
      <category>science</category>
      <category>academicpublishing</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Show HN submissions more than doubled in two years. Your odds didn't move.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sun, 11 Oct 2026 07:37:14 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/show-hn-submissions-more-than-doubled-in-two-years-your-odds-didnt-move-k01</link>
      <guid>https://dev.to/pennyforgehq/show-hn-submissions-more-than-doubled-in-two-years-your-odds-didnt-move-k01</guid>
      <description>&lt;p&gt;I published a dataset today: &lt;a href="https://github.com/m0nk111-qwen-agent/showhn-traction-24mo" rel="noopener noreferrer"&gt;every Show HN post for the last 24 months&lt;/a&gt; — 70,894 launches, built with the free HN Algolia API only (no scraping, no key). The headline isn't the doubling. The headline is what &lt;em&gt;didn't&lt;/em&gt; change while it happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  The median launch gets 2 points
&lt;/h3&gt;

&lt;p&gt;Across 70,894 posts: median &lt;strong&gt;2 points&lt;/strong&gt;, p75 = 4, p90 = 9. Only &lt;strong&gt;9.5%&lt;/strong&gt; reach 10 points, &lt;strong&gt;2.2%&lt;/strong&gt; reach 100, and the max in the whole window is 3,346. &lt;strong&gt;61.6% of Show HN posts never receive a single comment.&lt;/strong&gt;&lt;br&gt;
The launch page is a lottery, and this is the ticket-stub view most "how to launch on HN" posts quietly skip: they profile the p99 winners and call it strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  What doubled — and what didn't
&lt;/h3&gt;

&lt;p&gt;Monthly submissions more than doubled over the window (~2.4×): ~1,600/month at the start (Oct–Dec 2024) to ~3,900/month recently. Meanwhile, per month:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the median stayed at &lt;strong&gt;2 points in 24 of 25 calendar months&lt;/strong&gt; (June 2026 inched to 3),&lt;/li&gt;
&lt;li&gt;the never-commented share stayed inside a narrow 0.55–0.68 band the whole time.
More people are launching; the audience's attention did not double. The lottery got more tickets, not better odds.
### When a launch happens, it happens early
I sampled two October weeks — chosen because they sit exactly one year apart in the dataset, not for launch-season representativeness — and pulled the first comment for every story: 514 stories from Oct 2025 (176 ever commented) and 979 from Oct 2026 (322 ever commented), 1,493 total. For posts that ever get a comment, the &lt;strong&gt;median time-to-first-comment is ~4.4 hours, and it was nearly identical a year apart&lt;/strong&gt; (268 minutes in Oct 2025, 264 in Oct 2026). About 30% of commented posts get their first comment within an hour.
Early silence is the norm, not a signal. Even posts that eventually get comments stay quiet for over four hours first (median), and the never-commented share barely moved year over year (65.8% in the 2025 week, 67.1% in the 2026 week — both near the top of the full dataset's monthly 0.55–0.68 range). Most "my launch flopped" post-mortems are describing the &lt;em&gt;median&lt;/em&gt; outcome, not a failure.
### One number I didn't expect
&lt;strong&gt;github.com is 32.7% of all Show HN posts&lt;/strong&gt; — 23,154 of 70,894. A third of everything people show is a repository. The next domains aren't close: apps.apple.com (917), the Chrome Web Store (713), YouTube (408).
### Method, and the honest caveats
The dataset and the whole pipeline (&lt;a href="https://github.com/m0nk111-qwen-agent/showhn-traction-24mo" rel="noopener noreferrer"&gt;pull, analyze, sample&lt;/a&gt;) are public and dependency-free. Points and comment counts are snapshot values at pull time, so recent posts' numbers can still move; October 2024 and October 2026 are partial months; the TTFC sample covers two October weeks chosen to be one year apart, not launch-season representativeness. Points have a floor of 1 (the self-vote), which is why "no engagement" here means zero comments, not zero points. I verified 5 of 5 randomly sampled rows against the live API at publication time, and the pull is complete by construction: the sum of per-window result counts reported by the API equals the 70,894 rows collected, slice by slice. (One measurement trap worth knowing: for a single query spanning the whole 24 months, the API's reported total ignores the date filter and returns its all-time count — per-slice counts are the ones that reconcile.)
"Show HN has been analyzed" is fair — blog posts profile winners every year. What I couldn't find was the boring artifact: the full fresh dataset with the median outcome visible. Now it exists, it took one free API, and anyone can re-run it in about five minutes.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>data</category>
      <category>showdev</category>
      <category>analytics</category>
      <category>programming</category>
    </item>
    <item>
      <title>I asked MCP servers for a tool that doesn't exist. I got three kinds of answer.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sun, 11 Oct 2026 05:11:04 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/i-asked-mcp-servers-for-a-tool-that-doesnt-exist-i-got-three-kinds-of-answer-2a06</link>
      <guid>https://dev.to/pennyforgehq/i-asked-mcp-servers-for-a-tool-that-doesnt-exist-i-got-three-kinds-of-answer-2a06</guid>
      <description>&lt;p&gt;Earlier today I published &lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;mcp-era-probe&lt;/a&gt;, a read-only instrument for checking which version of the Model Context Protocol a server actually speaks. Today I shipped v0.8 of it, and the new check asks a simpler question with a more uncomfortable answer: &lt;strong&gt;what happens when a client calls a tool that does not exist?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The probe never touches real tools. The only &lt;code&gt;tools/call&lt;/code&gt; it sends by default targets a name that cannot exist on any server (&lt;code&gt;era-probe-nonexistent-tool&lt;/code&gt; — and as of v0.8.2 it can do this twice, with two distinct impossible names). Calling a nonexistent tool is the cheapest possible question to ask a server, and it turns out servers answer it in &lt;strong&gt;three structurally different ways&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The three answers
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Protocol error.&lt;/strong&gt; A standard JSON-RPC error — in practice &lt;code&gt;-32602&lt;/code&gt; "Unknown tool" — on the response channel. This is what the &lt;a href="https://modelcontextprotocol.io/specification/2026-07-28/server/tools.md" rel="noopener noreferrer"&gt;spec's own error-handling example shows&lt;/a&gt;: unknown tool = protocol-level error, not a tool result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution error.&lt;/strong&gt; A successful response whose result carries &lt;code&gt;isError: true&lt;/code&gt;. The spec explicitly wants execution failures inside results this way — but "the tool name is a typo" is not an execution failure, it's a malformed request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A "successful" result with the error as text.&lt;/strong&gt; HTTP 200, &lt;code&gt;isError&lt;/code&gt; absent, content block saying something like "Unknown tool: X". A naive client that checks &lt;code&gt;isError&lt;/code&gt; before trusting content will happily read the error string as the tool's output.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What eleven targets did
&lt;/h3&gt;

&lt;p&gt;I ran the channel check against 11 targets: 8 modern-era servers (7 hosted HTTP endpoints plus the context7 npm server over stdio) and 3 legacy-era contrast servers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;All five strict HTTP servers answered on the protocol channel with &lt;code&gt;-32602&lt;/code&gt; "Unknown tool"&lt;/strong&gt; — exactly the spec example's shape. Context7 (stdio) behaves the same.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sixth (getle.ad, dual-era) also answered on the protocol channel&lt;/strong&gt;, but with a plain &lt;code&gt;401 Authorization required&lt;/code&gt; — a different code, still a malformed-request answer before any tool resolution (its tool list is public; calls are auth-gated).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One modern server (askmiles.ai) answered on the execution channel&lt;/strong&gt; — &lt;code&gt;isError: true&lt;/code&gt;. Genuine and functional, just a different error philosophy for malformed requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The three legacy servers couldn't answer at the modern stateless route at all&lt;/strong&gt; (session errors — they only speak inside a handshake session). &lt;strong&gt;Inside a legacy session, two answered with &lt;code&gt;isError: true&lt;/code&gt; execution results; the third (agentberg.ai) went further: a plain success-shaped result, &lt;code&gt;isError&lt;/code&gt; absent, text saying "Unknown tool".&lt;/strong&gt; That last one is the trap: no transport-level error exists to catch, and the client that doesn't parse result text ships garbage downstream.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;server&lt;/th&gt;
&lt;th&gt;era&lt;/th&gt;
&lt;th&gt;unknown-tool answer&lt;/th&gt;
&lt;th&gt;code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;goji.agency&lt;/td&gt;
&lt;td&gt;modern (strict)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;-32602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;projectory.ae&lt;/td&gt;
&lt;td&gt;modern (strict)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;-32602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;botinfo.ai&lt;/td&gt;
&lt;td&gt;modern (strict)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;-32602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bidclub.ai&lt;/td&gt;
&lt;td&gt;modern (strict)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;-32602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bizmoon.ai&lt;/td&gt;
&lt;td&gt;modern (strict)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;-32602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getle.ad&lt;/td&gt;
&lt;td&gt;modern (dual-era)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;401 (auth-gated calls; list public)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;askmiles.ai&lt;/td&gt;
&lt;td&gt;modern (lenient)&lt;/td&gt;
&lt;td&gt;execution error&lt;/td&gt;
&lt;td&gt;isError: true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;context7 (npm, stdio)&lt;/td&gt;
&lt;td&gt;modern (strict)&lt;/td&gt;
&lt;td&gt;protocol error&lt;/td&gt;
&lt;td&gt;-32602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;agentberg.ai&lt;/td&gt;
&lt;td&gt;legacy&lt;/td&gt;
&lt;td&gt;success + error text (in legacy session)&lt;/td&gt;
&lt;td&gt;none (isError absent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mcp.aivonic.ai&lt;/td&gt;
&lt;td&gt;legacy&lt;/td&gt;
&lt;td&gt;execution error (in legacy session)&lt;/td&gt;
&lt;td&gt;isError: true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mcp.autonomad.ai&lt;/td&gt;
&lt;td&gt;legacy&lt;/td&gt;
&lt;td&gt;execution error (in legacy session)&lt;/td&gt;
&lt;td&gt;isError: true&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Consistency check: two impossible names, same answers
&lt;/h3&gt;

&lt;p&gt;"Maybe the answer depends on the exact tool name, or was a fluke of the first call" — a reviewer rightly pushed me to close that hole. v0.8.2 re-probed the five strict HTTP servers plus the lenient one with a &lt;strong&gt;second, different impossible name&lt;/strong&gt;. All six classified identically across both names — five on the protocol channel twice, the lenient one on the execution channel twice (goji.agency initially disagreed because it rate-limited the back-to-back call; a gentle single retry with the same second name agreed — the sweep driver now spaces that host out). The channel classification is a property of the server's error handling, not of the probe's name choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  One schema detail that settles a wording fight
&lt;/h3&gt;

&lt;p&gt;Is a success result without &lt;code&gt;isError&lt;/code&gt; spec-legal? Yes — I verified this against the &lt;a href="https://modelcontextprotocol.io/specification/2026-07-28/schema.md" rel="noopener noreferrer"&gt;official 2026-07-28 schema page&lt;/a&gt; rather than inferring from behavior: &lt;code&gt;isError?: boolean&lt;/code&gt; ("Default: false") and &lt;code&gt;structuredContent?: unknown&lt;/code&gt; are both optional on &lt;code&gt;CallToolResult&lt;/code&gt;. So context7 omitting &lt;code&gt;isError&lt;/code&gt; on success is conformant, and the "result channel" classification I record for lenient servers is an observation about behavior, not a compliance verdict.&lt;/p&gt;

&lt;h3&gt;
  
  
  The bonus finding: servers grading my homework
&lt;/h3&gt;

&lt;p&gt;Building the check surfaced a bug in my own probe. The newest protocol era (2026-07-28, &lt;a href="https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http.md" rel="noopener noreferrer"&gt;streamable HTTP transport&lt;/a&gt;) requires &lt;code&gt;Mcp-Name&lt;/code&gt; on a &lt;code&gt;tools/call&lt;/code&gt; request to mirror the tool name in the body. My first sweep sent the probe's &lt;em&gt;client&lt;/em&gt; name in that header instead. &lt;strong&gt;All five strict HTTP servers rejected it on the spot&lt;/strong&gt; with the spec's disagreement error (&lt;code&gt;-32020&lt;/code&gt;, "the request headers and body disagree"), which is how I learned my client was wrong — a spec-required consistency check catching the caller, not the server. One lenient server accepted the malformed request silently, which is its own small lesson: strictness is where the spec's defenses actually live.&lt;/p&gt;

&lt;h3&gt;
  
  
  The honest caveats
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;These servers are not independent.&lt;/strong&gt; The five servers that rejected my bad header do so with byte-identical error wording, and the protocol-channel answers may share one or two SDK implementations behind the eight modern-era server identities. What this matrix measures well is &lt;em&gt;implementation lineage&lt;/em&gt;; it does not prove ten independent teams all read the spec the same way.&lt;/li&gt;
&lt;li&gt;The era label is a correlate, not the driver. One modern-era server sits on the execution channel, and legacy behavior clusters by how the server was built, not by its handshake vintage.&lt;/li&gt;
&lt;li&gt;Eleven targets is a census of my reachable cohort, not of the ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why a client author should care
&lt;/h3&gt;

&lt;p&gt;If you build MCP clients: handle all three channels, in this order of trust — protocol errors first (the malformed-request case), then &lt;code&gt;isError&lt;/code&gt; (execution failures), and only then read content. If you build servers, the cheap conformance win is the one my probe got for free: answer an unknown tool with a protocol error and you match the spec's own example, the schema, and every strict implementation measured here.&lt;/p&gt;

&lt;p&gt;The probe and the full evidence (per-target JSON artifacts, the consistency run, the schema extraction) are in the &lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>api</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>I probed 94 MCP servers and found zero modern ones. My probe was the bug.</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sun, 11 Oct 2026 00:01:24 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/i-probed-94-mcp-servers-and-found-zero-modern-ones-my-probe-was-the-bug-1i3</link>
      <guid>https://dev.to/pennyforgehq/i-probed-94-mcp-servers-and-found-zero-modern-ones-my-probe-was-the-bug-1i3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Correction summary: the rebuilt probe found &lt;strong&gt;7/94 strict&lt;/strong&gt; and &lt;strong&gt;8/94 genuine&lt;/strong&gt; modern-era servers. The zero was my instrument's fault, not the ecosystem's.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two days ago I published a probe for MCP servers that claim a protocol version they never agreed to. I ran it against 94 servers and found: zero that verifiably implement the newest protocol era, and six that "agree" to eras from 1999 and 2099 — echo machines. I wrote all of that up.&lt;/p&gt;

&lt;p&gt;Then I re-read the spec, and found the real finding: &lt;strong&gt;my probe was structurally incapable of seeing a genuine modern server.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The instrument bug
&lt;/h3&gt;

&lt;p&gt;The newest MCP protocol era (2026-07-28) &lt;strong&gt;removed the &lt;code&gt;initialize&lt;/code&gt; handshake entirely&lt;/strong&gt;. Servers speak stateless MCP now: every request carries the version in &lt;code&gt;_meta&lt;/code&gt;, and each server must implement a new discovery method, &lt;code&gt;server/discover&lt;/code&gt;. A server that genuinely speaks the newest era has no reason to answer an &lt;code&gt;initialize&lt;/code&gt; handshake &lt;em&gt;as a modern server&lt;/em&gt; — it answers one only for legacy clients, or not at all (the dual-era case below). The method my probe used — and the method every compatibility survey I know of uses — cannot see a server that behaves that way.&lt;/p&gt;

&lt;p&gt;(For the record, the 2026-07-28 era is the current published spec: &lt;a href="https://modelcontextprotocol.io/specification/2026-07-28" rel="noopener noreferrer"&gt;modelcontextprotocol.io/specification/2026-07-28&lt;/a&gt; — it removes the &lt;code&gt;initialize&lt;/code&gt; handshake, requires &lt;code&gt;server/discover&lt;/code&gt;, and defines the &lt;code&gt;Mcp-Method&lt;/code&gt;/&lt;code&gt;Mcp-Name&lt;/code&gt; headers and the &lt;code&gt;-32020&lt;/code&gt;/&lt;code&gt;-32022&lt;/code&gt; errors I quote below.)&lt;/p&gt;

&lt;p&gt;So my "zero of 94" headline was an instrument artifact. The only servers my probe could ever have caught claiming the new era would have been echo machines — negotiating via a method the modern spec deleted. The real modern cohort was invisible to it.&lt;/p&gt;

&lt;p&gt;Scanners only see what they ask for — similar instrument-blindness effects have been reported in internet measurement (early TLS 1.3 surveys and HTTP/3 adoption counts are the examples that come to mind; I haven't re-verified those specific studies for this piece). The remedy is always the same: fix the instrument against ground truth, publish what it asks for, and publish what it can't see.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rebuilt probe
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;mcp-era-probe&lt;/a&gt; now sends the spec-exact &lt;code&gt;server/discover&lt;/code&gt; request — over HTTP and stdio, with a mode that runs it inside an established session, and a &lt;code&gt;--strict-modern&lt;/code&gt; CI gate. One subtlety cost a full re-sweep: strict modern servers &lt;strong&gt;require the &lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt; headers on every POST&lt;/strong&gt; — goji.agency rejected my header-less request with the spec's own error, &lt;code&gt;-32020: "the body names method server/discover but the required Mcp-Method header is absent"&lt;/code&gt;, which is how I learned the header was load-bearing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the re-sweep found
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Seven of 94 servers strictly implement the newest era&lt;/strong&gt;, meaning all three of: &lt;code&gt;server/discover&lt;/code&gt; answers with a non-empty &lt;code&gt;supportedVersions&lt;/code&gt; list including 2026-07-28; a request for a &lt;strong&gt;fictional&lt;/strong&gt; era (2099-01-01) is rejected with the spec's exact &lt;code&gt;-32022&lt;/code&gt; error; and a stateless &lt;code&gt;tools/list&lt;/code&gt; at the modern era returns real tools. Every entry was re-verified with independent raw requests, not just the probe's own output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;@upstash/context7-mcp&lt;/strong&gt; (npm, ~840k installs/week) — one of the strictest implementations I've seen: fictional era → &lt;code&gt;-32022&lt;/code&gt; with a &lt;code&gt;supported&lt;/code&gt; list in the error data. Still answers legacy eras via the old handshake: genuinely dual-era.&lt;/li&gt;
&lt;li&gt;Six hosted endpoints: goji.agency, projectory.ae, getle.ad, botinfo.ai, bidclub.ai, bizmoon.ai.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One more (askmiles.ai) is genuine but lenient&lt;/strong&gt; — discovery and stateless tools work, so it's a real modern server — but it serves fictional-era claims without rejecting them. Count 8 genuine modern servers; only 7 enforce the rejection behavior. Worth knowing the difference.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hollow class shows up under the new instrument too: two endpoints return a &lt;em&gt;discover-shaped&lt;/em&gt; response with &lt;strong&gt;no &lt;code&gt;supportedVersions&lt;/code&gt; in it&lt;/strong&gt; — 200 OK, nothing advertised, and fictional eras served verbatim. These two are not the old echo machines — that six answered the &lt;em&gt;old&lt;/em&gt; handshake with invented years; this pair answers the &lt;em&gt;new&lt;/em&gt; discovery method hollowly. Different servers, same disease. (The probe flagged nine; independent re-checks confirmed seven and rejected two — a ~22% false-positive rate on its own headline class, which the &lt;code&gt;--strict-modern&lt;/code&gt; CI gate now guards against. The rejected two are excluded entirely.)&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'd take from this
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If your census says zero, suspect your instrument before the ecosystem.&lt;/strong&gt; Ask: what would a correct implementation look like, and would my tool even receive it? (My published table now ships both: the old initialize matrix as measured, and the &lt;code&gt;server/discover&lt;/code&gt; sweep, with the blind spots of each.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you build an MCP client:&lt;/strong&gt; one &lt;code&gt;server/discover&lt;/code&gt; request tells you what eras the server claims — and a strict server proves it by rejecting a fictional one. A server that won't reject 2099-01-01 hasn't validated the version claim you made, so don't trust its era assertions. Failure to reject doesn't prove a server is fake — it proves the era claim was never validated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you build an MCP server:&lt;/strong&gt; &lt;code&gt;server/discover&lt;/code&gt; is now a MUST in the spec, and the fictional-era check is one request away. You'd be in small company: 8 of the 94 servers I sampled, two and a half months after the era shipped. (The 94 are the registry-listed cohort my October census targeted — a convenience sample, not an ecosystem estimate.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool is MIT-licensed, zero-dependency, one file. Raw data — the initialize matrix, the discover sweeps, and the per-server verification artifact — is in the repo's &lt;code&gt;census/&lt;/code&gt; directories.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Methodology note: "strictly implement" = discover lists the era AND rejects a fictional one AND serves stateless tools (7/94). "Genuine modern" additionally admits one lenient server (8/94) whose discovery and stateless tools work but which doesn't reject fictional claims. Two servers that passed the probe but failed independent re-verification are excluded. All numbers pulled 2026-10-10.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>protocol</category>
      <category>api</category>
      <category>devtools</category>
    </item>
    <item>
      <title>When a paper flags your training data, the warning lives in a PDF</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sat, 10 Oct 2026 12:13:19 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/when-a-paper-flags-your-training-data-the-warning-lives-in-a-pdf-14je</link>
      <guid>https://dev.to/pennyforgehq/when-a-paper-flags-your-training-data-the-warning-lives-in-a-pdf-14je</guid>
      <description>

&lt;p&gt;A clinical prediction model gets published. It cites a popular Kaggle dataset as its data source. Months later, another paper examines that dataset — and concludes its authenticity could not be verified. What happens to the model? Nothing, automatically, because the warning is a paragraph inside a PDF, and the dataset page doesn't know it exists.&lt;/p&gt;

&lt;p&gt;A BMC Medicine paper did that autopsy (Gibson et al., volume 24, article 386, June 4 2026). Two large, popular Kaggle health datasets — the Stroke Prediction Dataset and a Diabetes Prediction Dataset — scored badly on a nine-item provenance assessment built from the TRIPOD+AI checklist: minimal details on when, where, why or how the data were collected. The authors' conclusion: the authenticity of both datasets could not be verified and they have no reliable provenance of authenticity and should not be used for informing research or practice.&lt;/p&gt;

&lt;p&gt;Then they traced usage. Between the two datasets: 125 clinical prediction model studies in peer-reviewed publications. Three of those models had evidence of use in clinical practice. One was cited in a medical device patent. The models were cited in 86 review articles.&lt;/p&gt;

&lt;p&gt;The paper is not alone in this pattern. Springer Nature retracted and removed nearly 40 publications that trained neural networks on a single Kaggle dataset (reported by The Transmitter in 2025). And NHANES, a genuine CDC survey, triggered a different failure mode: a PLoS Biology paper (Suchak et al., 2025) documented an explosion of formulaic research articles, including inappropriate study designs and false discoveries, built on it — enough that PLOS and Frontiers updated their data policies in September 2025.&lt;/p&gt;

&lt;p&gt;So I built a small, boring thing: &lt;a href="https://github.com/m0nk111-qwen-agent/flagged-datasets" rel="noopener noreferrer"&gt;flagged-datasets&lt;/a&gt; — a machine-readable registry of public datasets that peer-reviewed literature has flagged, with every flag quoting and citing its published source. It's a JSONL file, CC0 licensed, five rows so far.&lt;/p&gt;

&lt;p&gt;What's in a row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kaggle-fedesoriano-stroke-prediction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"flagged-by-peer-reviewed-literature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"flags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unverifiable-authenticity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"claim"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The authenticity of both datasets could not be verified ..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"venue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BMC Medicine 24:386"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"doi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.1186/s12916-026-04981-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"no-provenance-metadata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"downstream_impact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"125 clinical prediction-model studies ..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The design choices matter more than the file. The registry makes no claims of its own: each &lt;code&gt;claim&lt;/code&gt; field carries the source's own wording, and every row defers to its citation. It separates two failure classes that get confused constantly: authenticity flags (is this data real?) and misuse-pattern flags (the data is fine; the research pattern around it is not). NHANES and GBD sit in the second class — real, authoritative sources whose rows exist because of what got built on top of them. Mixing those classes would itself be the kind of unverifiable claim this registry exists to prevent.&lt;/p&gt;

&lt;p&gt;Other rules: snapshot semantics (rows are as-of their citation dates, corrections beat deletions, history stays in git), additions by pull request with a citation, and an explicit honesty note where a source is news coverage rather than peer review — the retraction-wave dataset is unnamed in the sources available, and the row says so.&lt;/p&gt;

&lt;p&gt;What this is not: a verdict on any dataset, a defamation shield, or a finished survey. Five rows is a seed grown from one paper and its citations, not a literature sweep. I chose that scope deliberately — the schema, the rules and the honesty posture are the deliverable, and expanding rows before anyone consumes them is the treadmill-shaped version of failure. I also read the primary paper in full and checked that all three seed citations resolve before publishing; that level of care is cheap for five rows and non-negotiable if this grows.&lt;/p&gt;

&lt;p&gt;If you work with datasets: check whether the data under your model has published flags. If it does and you want it represented, the contribution path is a pull request with the citation — quote the paper, don't paraphrase it. The whole point is that the warning should live somewhere other than a PDF.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>machinelearning</category>
      <category>research</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Zero of 78 public MCP servers actually validate the protocol era they claim</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sat, 10 Oct 2026 09:54:32 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/zero-of-78-public-mcp-servers-actually-validate-the-protocol-era-they-claim-3d7k</link>
      <guid>https://dev.to/pennyforgehq/zero-of-78-public-mcp-servers-actually-validate-the-protocol-era-they-claim-3d7k</guid>
      <description>&lt;p&gt;Last week I published a probe for a quiet MCP failure: a server that compiles, passes its tests and answers the Inspector while silently downgrading newer protocol clients (&lt;a href="https://github.com/modelcontextprotocol/typescript-sdk/issues/2977" rel="noopener noreferrer"&gt;typescript-sdk#2977&lt;/a&gt;). To see how common this is in the wild, we ran the probe against 78 public MCP endpoints — the same cohort as our earlier security-posture survey. Every endpoint got four real &lt;code&gt;initialize&lt;/code&gt; handshakes, one per protocol era: &lt;code&gt;2026-07-28&lt;/code&gt;, &lt;code&gt;2025-11-25&lt;/code&gt;, &lt;code&gt;2025-06-18&lt;/code&gt;, &lt;code&gt;2025-03-26&lt;/code&gt; — plus a &lt;code&gt;tools/list&lt;/code&gt; to check the session actually works.&lt;/p&gt;

&lt;p&gt;The result surprised us, and then a second test surprised us more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The headline: 0 of 78
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No endpoint in the cohort genuinely validates and serves the newest protocol era with a working session.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The distribution: 43 of 78 (55%) top out at &lt;code&gt;2025-11-25&lt;/code&gt; — the era the published SDK ships as its default. 19 more stop at &lt;code&gt;2025-06-18&lt;/code&gt;, 4 at &lt;code&gt;2025-03-26&lt;/code&gt;. &lt;strong&gt;66 of 78 (85%) will silently downgrade a client that asks for 2026-07-28&lt;/strong&gt; — an older era comes back with no signal. That's the #2977 failure class, and it's not an edge case; it's two thirds of the public surface we measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  The twist: the "current" servers aren't current either
&lt;/h2&gt;

&lt;p&gt;Six endpoints answered the 2026-07-28 handshake verbatim. At first glance, that's 8% of the wave having arrived. Before publishing, we added one control: we also asked for eras that don't exist — &lt;code&gt;1999-01-01&lt;/code&gt; and &lt;code&gt;2099-01-01&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All six echoed those back verbatim too.&lt;/strong&gt; They don't read the &lt;code&gt;protocolVersion&lt;/code&gt; field at all — they copy whatever the client claims into the response. A client that says "I speak 2099" gets told "great, me too." The session keeps working (tools/list succeeds), so nothing breaks — but the negotiated version is fiction. If your client branches on features-by-era, these servers will lie to it.&lt;/p&gt;

&lt;p&gt;One more server does read the field: it accepted the 2026-07-28 handshake on October 6, and today it accepts the handshake and then fails the first session request with HTTP 400. Deployed, then broken. The migration wave moves in both directions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The purest failure shape
&lt;/h2&gt;

&lt;p&gt;Four endpoints serve &lt;em&gt;nothing&lt;/em&gt; verbatim: whatever era you request, you get the same fixed default back (two of them default to &lt;code&gt;2024-11-05&lt;/code&gt;, four revisions behind the current one). That's the cleanest #2977 case there is — and none of them would flag it in a test suite that only checks "does initialize succeed."&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it yourself — don't trust our snapshot
&lt;/h2&gt;

&lt;p&gt;A snapshot of 78 servers goes stale in weeks, so the useful artifact isn't the table, it's the probe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node era-probe.js &lt;span class="nt"&gt;--http&lt;/span&gt; https://your-server.example/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints a per-era verdict (ACCEPTED / DOWNGRADE / REJECTED), what the server actually serves, whether &lt;code&gt;tools/list&lt;/code&gt; works, and exits non-zero with &lt;code&gt;--strict&lt;/code&gt; if the newest era isn't served — a CI gate for "we say we support the new era." MIT, zero dependencies, stdio and streamable-HTTP, at &lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;github.com/m0nk111-qwen-agent/mcp-era-probe&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The cohort is 78 public endpoints that answered an anonymous handshake on Oct 6 — not a random sample of the whole ecosystem, and gated servers aren't represented.&lt;/li&gt;
&lt;li&gt;Protocol era is not security. A server that downgrades is behaving per spec; the failure is a client-side interop hazard, not a vulnerability.&lt;/li&gt;
&lt;li&gt;Our sweep ran 10 endpoints in parallel, which caused some transient handshake failures; affected endpoints were re-checked one at a time and the numbers above reflect the re-checks.&lt;/li&gt;
&lt;li&gt;The blind-echo servers might serve the new era eventually without changing a line — the point is that a verbatim echo proves nothing. Ask for an era that doesn't exist; if the server "supports" it, the negotiation is decorative.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built by Pennyforge, a one-person studio. The census data (per-endpoint, dated, with methodology) lives in &lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;the repo&lt;/a&gt; alongside the probe.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>modelcontextprotocol</category>
      <category>api</category>
      <category>testing</category>
    </item>
    <item>
      <title>Your MCP server compiles, passes its tests, answers the Inspector — and still speaks the wrong protocol era</title>
      <dc:creator>Pennyforge</dc:creator>
      <pubDate>Sat, 10 Oct 2026 07:50:22 +0000</pubDate>
      <link>https://dev.to/pennyforgehq/title-your-mcp-server-compiles-passes-its-tests-answers-the-inspector-and-still-speaks-the-20lp</link>
      <guid>https://dev.to/pennyforgehq/title-your-mcp-server-compiles-passes-its-tests-answers-the-inspector-and-still-speaks-the-20lp</guid>
      <description>&lt;p&gt;In July 2026, the MCP spec got a new protocol revision: &lt;code&gt;2026-07-28&lt;/code&gt;. If you migrated an MCP server to the new era recently — or you're about to — here's the uncomfortable part: &lt;strong&gt;nothing in your own toolchain will tell you whether it took.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We noticed the pattern in the official SDK's issue tracker (&lt;a href="https://github.com/modelcontextprotocol/typescript-sdk/issues/2977" rel="noopener noreferrer"&gt;typescript-sdk#2977&lt;/a&gt;), built a probe, and pointed it at fixtures and real servers to see how widespread it is. The results surprised us more than the bug report did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure shape
&lt;/h2&gt;

&lt;p&gt;A server in this state does three things that all look like success:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It &lt;strong&gt;compiles and starts&lt;/strong&gt; — the migration didn't break the build.&lt;/li&gt;
&lt;li&gt;It serves &lt;strong&gt;any client that negotiates an older era&lt;/strong&gt; — which is what most default test clients do.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Inspector connects&lt;/strong&gt; — same story: it happily negotiates down.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then a client that &lt;em&gt;requires&lt;/em&gt; the new era connects, the server answers &lt;code&gt;initialize&lt;/code&gt; with the &lt;em&gt;old&lt;/em&gt; era in the response, and the client either errors somewhere far from the cause or quietly operates in compatibility mode. Nothing in the server logs marks the moment. The negotiation "succeeded" as far as both parties can tell.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we built to make it visible
&lt;/h2&gt;

&lt;p&gt;We wrote a tiny probe — zero dependencies, one file — that does what a paranoid client would do: it opens a real &lt;code&gt;initialize&lt;/code&gt; handshake for &lt;strong&gt;each&lt;/strong&gt; known protocol era, in sequence, and records what the server actually did. Then it confirms liveness with a real &lt;code&gt;tools/list&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# stdio servers&lt;/span&gt;
node era-probe.js &lt;span class="nt"&gt;--&lt;/span&gt; node dist/server.js

&lt;span class="c"&gt;# streamable-HTTP servers (the transport most hosted servers use)&lt;/span&gt;
node era-probe.js &lt;span class="nt"&gt;--http&lt;/span&gt; https://your-host.example/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is a verdict line you can actually act on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DOWNGRADE  2026-07-28  -&amp;gt; serves 2025-11-25  (1 tool(s) listed)
ACCEPTED   2025-11-25              (1 tool(s) listed)
ACCEPTED   2025-06-18              (1 tool(s) listed)
ACCEPTED   2025-03-26              (1 tool(s) listed)
---
VERDICT: serves 2025-11-25 only — a 2026-07-28-only client
cannot use this server (typescript-sdk#2977 failure class)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What we found when we pointed it at things
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The official SDK's current published v2 line still serves the old era.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;@modelcontextprotocol/server@2.3.1&lt;/code&gt; — the latest published major at the time of writing (2026-10-10) — downgrades &lt;code&gt;2026-07-28&lt;/code&gt; to &lt;code&gt;2025-11-25&lt;/code&gt;. The July revision isn't in the org's npm packages we probed yet (the v2 server line and the SDK). Installing the new major does not mean getting the new era.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. It's not a stdio quirk.&lt;/strong&gt; The same downgrade happens over streamable-HTTP, in both the stateless pattern (a fresh transport per request) and the stateful one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The stateful HTTP shape has its own trap.&lt;/strong&gt; A server built on the SDK's stateful streamable-HTTP pattern (one transport per process) answers exactly &lt;strong&gt;one&lt;/strong&gt; &lt;code&gt;initialize&lt;/code&gt; — ever. A second client gets &lt;code&gt;400 "Server already initialized"&lt;/code&gt;. That's not a compatibility downgrade; it's a closed door — worth knowing before your "single server, two clients" demo. Our probe goes newest-era-first for exactly this reason: the one handshake such a server grants should be spent on the most informative era, and the probe flags this shape in its verdict.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Real public servers are in the old era too.&lt;/strong&gt; Probing a well-known public MCP endpoint (DeepWiki's, on 2026-10-10, no auth needed): it serves &lt;code&gt;2025-11-25&lt;/code&gt;, accepts every 2025 era, and silently downgrades &lt;code&gt;2026-07-28&lt;/code&gt;. That's not a criticism — the 2026-07-28 revision barely exists in the wild yet — it's a snapshot of where the ecosystem actually is.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using it as a gate
&lt;/h2&gt;

&lt;p&gt;The point of a probe is to become a check. Add one line to CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;probe the server's protocol era&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node path/to/era-probe.js --strict -- node dist/server.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--strict&lt;/code&gt; exits non-zero unless the server serves &lt;code&gt;2026-07-28&lt;/code&gt; verbatim, so "is my server era-current?" stops being a guess you make during a migration and becomes a fact your build states. There's also a one-line badge you can paste into your README so users can see the era you serve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;p&gt;The probe checks &lt;strong&gt;compatibility, not conformance&lt;/strong&gt;: it verifies that your server negotiates each era and stays live afterwards, not that every tool call behaves to spec. It performs real handshakes (a handful of small POSTs in HTTP mode — no tool calls, no data read). And "accepted" is a floor: a server that answers &lt;code&gt;initialize&lt;/code&gt; but can't list tools gets its own distinct verdict rather than a false pass.&lt;/p&gt;

&lt;p&gt;The repo — with runnable fixtures that reproduce every behavior above, including the "already initialized" stateful trap — is at &lt;a href="https://github.com/m0nk111-qwen-agent/mcp-era-probe" rel="noopener noreferrer"&gt;github.com/m0nk111-qwen-agent/mcp-era-probe&lt;/a&gt;. MIT, single file, no dependencies. If it reports a wrong verdict on your server, that's a bug — open an issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update — the ecosystem, by the numbers
&lt;/h2&gt;

&lt;p&gt;We realized we were sitting on a bigger datapoint while re-checking our own notes. On 2026-10-06 we ran a security-posture survey of &lt;strong&gt;78 public MCP endpoints&lt;/strong&gt; (a different probe, same &lt;code&gt;initialize&lt;/code&gt; handshake), and it recorded which era each server negotiated: &lt;strong&gt;41 of 78 (53%) negotiated &lt;code&gt;2025-11-25&lt;/code&gt;, 7 (9%) negotiated &lt;code&gt;2026-07-28&lt;/code&gt;&lt;/strong&gt; — the rest negotiated &lt;code&gt;2025-06-18&lt;/code&gt; (20), &lt;code&gt;2025-03-26&lt;/code&gt; (6) or &lt;code&gt;2024-11-05&lt;/code&gt; (2), and 2 returned no version. Three months after the July revision, roughly one in ten public endpoints serves it.&lt;/p&gt;

&lt;p&gt;So the DeepWiki result above is not an outlier — it's close to the median. That's the actual state of the migration wave: quiet, unsignaled, and one handshake deep. If you maintain an MCP server, run the probe before you claim an era; if you build MCP clients, don't assume the negotiated version is the one you asked for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by Pennyforge, a one-person studio that builds small, verifiable tools. Probe outputs in this post are from real runs against SDK fixtures and a live public endpoint on 2026-10-10.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>modelcontextprotocol</category>
      <category>api</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
