<?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: Amaresh Pelleti</title>
    <description>The latest articles on DEV Community by Amaresh Pelleti (@amareswer).</description>
    <link>https://dev.to/amareswer</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%2F3978481%2Fbef1aa2c-c07a-414a-bb88-ea788ca39ba2.jpg</url>
      <title>DEV Community: Amaresh Pelleti</title>
      <link>https://dev.to/amareswer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amareswer"/>
    <language>en</language>
    <item>
      <title>Git 3.0: What Actually Breaks (SHA-256, Rust, More)</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Thu, 24 Sep 2026 12:09:44 +0000</pubDate>
      <link>https://dev.to/amareswer/git-30-what-actually-breaks-sha-256-rust-more-1e5d</link>
      <guid>https://dev.to/amareswer/git-30-what-actually-breaks-sha-256-rust-more-1e5d</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/git-3-0-breaking-changes/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Git 3.0 changes the default hash function, the default reference storage format, the default branch name, and the build toolchain required to compile Git at all. This comes straight from git-scm.com's own BreakingChanges documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Repositories Default to SHA-256, Not SHA-1
&lt;/h2&gt;

&lt;p&gt;Git 3.0 changes the default hash function for new repositories from SHA-1 to SHA-256. NIST deprecated SHA-1 back in 2011, and Git has supported SHA-256 as an opt-in option since 2018. What's new is that SHA-256 becomes the default.&lt;/p&gt;

&lt;p&gt;Existing SHA-1 repositories keep working. This only affects repos created after you upgrade, using &lt;code&gt;git init&lt;/code&gt; without an explicit &lt;code&gt;--object-format=sha1&lt;/code&gt; flag. SHA-256 hashes are 64 hex characters instead of 40, so anything parsing commit hashes needs to handle both.&lt;/p&gt;

&lt;h2&gt;
  
  
  reftable Replaces the Files Backend by Default
&lt;/h2&gt;

&lt;p&gt;New repositories will default to storing references in the &lt;code&gt;reftable&lt;/code&gt; format instead of the traditional files-plus-packed-refs layout. This matters most for tools that read &lt;code&gt;.git/refs/&lt;/code&gt; directly instead of using &lt;code&gt;git for-each-ref&lt;/code&gt; or similar plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust Becomes Mandatory to Build Git
&lt;/h2&gt;

&lt;p&gt;This is the widest-reaching change. Git has adopted Rust gradually since Git 2.49, with every component staying optional — until now. The rollout has three stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Git 2.52&lt;/strong&gt; — Rust auto-detected by Meson, disabled by default in the Makefile build&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git 2.55&lt;/strong&gt; — both build systems default-enable Rust (already shipped)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git 3.0&lt;/strong&gt; — build options removed, Rust becomes mandatory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git developer Patrick Steinhardt described the approach to Phoronix as "a test balloon" meant to give the project time to build proper infrastructure and give distributors time to adjust toolchains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; if your CI builds Git from source instead of installing a package, check whether your build image has Rust support before Git 3.0 ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven Things Git 3.0 Removes Outright
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Grafting commits support&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git-pack-redundant&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Shorthand remote URLs in &lt;code&gt;$GIT_COMMON_DIR/branches/&lt;/code&gt; and &lt;code&gt;/remotes/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--stdin&lt;/code&gt; option on &lt;code&gt;git name-rev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git-whatchanged&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;core.commentString=auto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;core.preferSymlinkRefs=true&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;safe.bareRepository&lt;/code&gt; also changes its default from &lt;code&gt;all&lt;/code&gt; to &lt;code&gt;explicit&lt;/code&gt; — a real security-relevant change for automation that clones bare repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Check Before Git 3.0 Ships
&lt;/h2&gt;

&lt;p&gt;Phoronix reports a target of around end of 2026. Checklist: grep CI configs for the removed commands, confirm build images have Rust if compiling from source, check for direct &lt;code&gt;.git/refs/&lt;/code&gt; reads, and test that hash-parsing tooling handles 64-character hashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git 3.0 defaults new repos to SHA-256 instead of SHA-1; existing repos are unaffected&lt;/li&gt;
&lt;li&gt;New repos also default to &lt;code&gt;reftable&lt;/code&gt; instead of loose-files ref storage&lt;/li&gt;
&lt;li&gt;Rust becomes mandatory to build, rolling out across Git 2.52, 2.55, and 3.0&lt;/li&gt;
&lt;li&gt;Seven features removed outright, including &lt;code&gt;git-whatchanged&lt;/code&gt; and grafting&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;safe.bareRepository&lt;/code&gt; now defaults to &lt;code&gt;explicit&lt;/code&gt; instead of &lt;code&gt;all&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>opensource</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>ECS vs EKS: What Each One Actually Costs You</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Wed, 23 Sep 2026 10:14:24 +0000</pubDate>
      <link>https://dev.to/amareswer/ecs-vs-eks-what-each-one-actually-costs-you-57ic</link>
      <guid>https://dev.to/amareswer/ecs-vs-eks-what-each-one-actually-costs-you-57ic</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/ecs-vs-eks-cost-comparison/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ECS vs EKS comparisons usually stop at "ECS is simpler, EKS is more portable." That's true, but it skips the number that actually shows up on your AWS bill. ECS charges nothing to run the control plane. EKS charges $0.10 per cluster-hour for the first 14 months a Kubernetes version is supported, then $0.60 per cluster-hour once that version moves into extended support — a jump from roughly $73 a month to about $438 a month for a single cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Control Plane Price Everyone Skips
&lt;/h2&gt;

&lt;p&gt;ECS has no separate control-plane charge. AWS runs the scheduler, API, and task placement logic for free — you only pay for the EC2 or Fargate compute actually running your containers.&lt;/p&gt;

&lt;p&gt;EKS is different. Per AWS's own EKS pricing page, every cluster costs $0.10 per hour for standard support, covering a Kubernetes version for 14 months after release. Miss that window, and the same cluster jumps to $0.60 per hour under extended support for up to 12 more months. $0.10/hour is about $73/month. $0.60/hour is about $438/month — a 6x jump for leaving a cluster on an older version.&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;ECS&lt;/th&gt;
&lt;th&gt;EKS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control plane&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0.10/hour (standard support)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After 14 months, unpatched&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;$0.60/hour (extended support)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approx. monthly control-plane cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;$73 → $438&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute&lt;/td&gt;
&lt;td&gt;EC2 or Fargate, billed normally&lt;/td&gt;
&lt;td&gt;EC2 or Fargate, billed normally&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why the Extended Support Jump Catches Teams Off Guard
&lt;/h2&gt;

&lt;p&gt;It's not hidden — it's right on AWS's pricing page. What catches teams off guard is that it's a per-cluster charge tied to the Kubernetes version, not your application code. A cluster that sits forgotten for a year and a half is exactly the kind of cost that shows up as a surprise line item in a FinOps review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where ECS's Simplicity Argument Actually Holds
&lt;/h2&gt;

&lt;p&gt;ECS wins on cost and simplicity when your workload doesn't need Kubernetes-specific tooling. No control plane fee, no version-lifecycle clock, and task definitions are a smaller surface than Kubernetes manifests and CRDs.&lt;/p&gt;

&lt;p&gt;That has a limit. ECS's model is AWS-specific. Need to run the same workload elsewhere, or through Helm charts and ArgoCD? None of that transfers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where EKS's Cost Actually Pays for Itself
&lt;/h2&gt;

&lt;p&gt;EKS's fee buys the entire Kubernetes ecosystem — the same manifests, Helm charts, and GitOps tooling that work on GKE, AKS, or bare metal. If your team already runs Kubernetes anywhere else, that portability is worth more than $73 a month.&lt;/p&gt;

&lt;p&gt;EKS also supports Fargate, same as ECS, so "EKS forces node management" doesn't hold up anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Decision Criteria
&lt;/h2&gt;

&lt;p&gt;Pick ECS if you're AWS-only with no existing Kubernetes investment. Pick EKS if you need multi-cloud portability, or your team's tooling is already built around Kubernetes primitives.&lt;/p&gt;

&lt;p&gt;If you pick EKS, put the version upgrade on a real calendar — cheap to handle on schedule, expensive to ignore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ECS has no control-plane fee; EKS charges $0.10/cluster-hour standard, $0.60/cluster-hour extended support&lt;/li&gt;
&lt;li&gt;The extended-support jump (~$73/mo → ~$438/mo) hits clusters running Kubernetes versions older than 14 months&lt;/li&gt;
&lt;li&gt;ECS wins on simplicity and cost for AWS-only workloads&lt;/li&gt;
&lt;li&gt;EKS's fee buys real portability across any Kubernetes environment&lt;/li&gt;
&lt;li&gt;Both support Fargate — "EKS means managing nodes" isn't a real argument anymore&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Cursor Pricing: What the Plans Actually Give You</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Tue, 22 Sep 2026 09:50:00 +0000</pubDate>
      <link>https://dev.to/amareswer/cursor-pricing-what-the-plans-actually-give-you-4bla</link>
      <guid>https://dev.to/amareswer/cursor-pricing-what-the-plans-actually-give-you-4bla</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/cursor-pricing-explained/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cursor's pricing page lists four plans — Hobby, Pro, Pro+, and Ultra — but only one of them has a real number attached to what you get. Pro costs $20 a month for "extended limits on Agent." Pro+ costs $60 for "3x Pro limits." Ultra costs $200 for "20x Pro limits." Every tier above Hobby is defined as a multiple of Pro, and Pro's actual baseline isn't published anywhere on the page.&lt;/p&gt;

&lt;p&gt;That's not a documentation gap. It's the whole pricing model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Each Cursor Plan Actually Includes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hobby&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Limited Agent requests, access to Composer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;$20/mo&lt;/td&gt;
&lt;td&gt;Extended limits on Agent, frontier model access, cloud agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro+&lt;/td&gt;
&lt;td&gt;$60/mo&lt;/td&gt;
&lt;td&gt;3x Pro's Agent limit, higher Grok Bot usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ultra&lt;/td&gt;
&lt;td&gt;$200/mo&lt;/td&gt;
&lt;td&gt;20x Pro's Agent limit, priority access to new features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Teams&lt;/td&gt;
&lt;td&gt;$40–$120/seat&lt;/td&gt;
&lt;td&gt;Pooled usage across the team&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cursor's own pricing page describes every tier's allowance in relative terms without ever stating what one unit of usage costs. A reader on justinmckelvey.com summed it up: "Every tier is a multiple of Pro, and Pro is a multiple of nothing you can see."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Multiplier Pricing Actually Has a Pattern
&lt;/h2&gt;

&lt;p&gt;Compare tiers by dollar-per-unit instead of the marketing copy and something real shows up. Pro+ costs 3x Pro's price for 3x Pro's allowance — same $20 per unit, no discount for spending more. Ultra breaks that pattern: $200 for 20x Pro's allowance works out to $10 per unit, half the per-unit cost of Pro or Pro+.&lt;/p&gt;

&lt;p&gt;Ultra is the only tier that actually changes the underlying economics. Pro+ just buys more of the same rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor Router Changed What "Auto" Actually Bills
&lt;/h2&gt;

&lt;p&gt;Auto mode used to mean a flat rate no matter which model handled your request. That changed July 22, 2026, when Cursor Router replaced Auto's fixed heuristics with a classifier trained on 600,000+ real coding requests, picking a model per request across three modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence&lt;/strong&gt; — frontier-model quality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balance&lt;/strong&gt; — strong quality at lower cost, the default for most people&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt; — cheapest mode clearing a quality bar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cursor's numbers show Auto Intelligence at roughly 60% lower cost than running frontier models directly, and Balance at about 36% cheaper, with measured cost-per-commit of $6.76 (Intelligence) and $4.63 (Balance).&lt;/p&gt;

&lt;p&gt;The catch is billing, not quality. A user on Cursor's forum put it directly: "Auto, to me, used to mean 'cheap flat rate, don't worry which model actually ran behind the scenes.' I emphasized used to because as of today, this no longer holds." Auto Balance can route to an expensive frontier model and bill at its real rate — no separate warning shown.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When You Hit the Limit
&lt;/h2&gt;

&lt;p&gt;Cursor tracks two usage pools: Cursor Models (Grok 4.5–4.7, Composer 2.5) and Other Models (third-party, billed at provider rates). Usage resets monthly and doesn't roll over.&lt;/p&gt;

&lt;p&gt;Hit your limit and you get an in-editor notification with two choices: turn on on-demand pay-as-you-go usage, or upgrade tiers. Neither happens automatically. One widely shared example documented a team whose $7,000 annual subscription was consumed in a single day of normal usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; on-demand usage has no built-in spending cap of its own — check it periodically if you enable it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teams, Enterprise, and Legacy Max Mode Pricing
&lt;/h2&gt;

&lt;p&gt;Teams/Enterprise plans using their own API key pay a flat Cursor Token Rate of $0.25 per million tokens. Legacy Max Mode bills at the model's own API rate plus a 20% surcharge. Neither rate appears on the main pricing page — both are buried in the usage-limits docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pro ($20), Pro+ ($60, 3x Pro), Ultra ($200, 20x Pro) are priced as multipliers of an unpublished baseline — only Ultra lowers the per-unit cost&lt;/li&gt;
&lt;li&gt;Cursor Router (July 22, 2026) replaced fixed Auto-mode routing with per-request classification across Intelligence/Balance/Cost&lt;/li&gt;
&lt;li&gt;Auto Balance can bill frontier-model rates with no warning — check your invoice for unexpected model names&lt;/li&gt;
&lt;li&gt;Teams/Enterprise with their own key pay $0.25/million tokens; legacy Max Mode is API rate + 20%&lt;/li&gt;
&lt;li&gt;Hitting your limit doesn't auto-charge — you choose on-demand usage or an upgrade&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cursor</category>
      <category>ai</category>
      <category>pricing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Running Ollama in Production: systemd, TLS, and API Auth</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Mon, 21 Sep 2026 11:13:37 +0000</pubDate>
      <link>https://dev.to/amareswer/running-ollama-in-production-systemd-tls-and-api-auth-1b97</link>
      <guid>https://dev.to/amareswer/running-ollama-in-production-systemd-tls-and-api-auth-1b97</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/ollama-production-vps-hardening/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ollama production deployment means three things the official docs don't cover: the default systemd unit runs Ollama unsandboxed, the reverse-proxy example in Ollama's own FAQ has no TLS and no auth, and there's no built-in authentication at all — anyone who reaches the port can call the API. None of that is a bug; it's just out of scope for a quickstart. This closes the gap with the actual hardening steps.&lt;/p&gt;

&lt;p&gt;This is provider-agnostic — VPS, bare metal, home server, any Linux box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardening the systemd Service Beyond the Default Unit
&lt;/h2&gt;

&lt;p&gt;Ollama's installer creates a dedicated &lt;code&gt;ollama&lt;/code&gt; system user instead of running as root, and the default unit looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Ollama Service&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/ollama serve&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ollama&lt;/span&gt;
&lt;span class="py"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ollama&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"PATH=$PATH"&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reasonable baseline, not hardened. Add these via &lt;code&gt;sudo systemctl edit ollama&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;NoNewPrivileges&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;ProtectSystem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;strict&lt;/span&gt;
&lt;span class="py"&gt;ProtectHome&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;PrivateTmp&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;PrivateDevices&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;ProtectKernelTunables&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;ProtectKernelModules&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;ProtectControlGroups&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
&lt;span class="py"&gt;ReadWritePaths&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/share/ollama/.ollama&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ProtectSystem=strict&lt;/code&gt; makes the filesystem read-only except API filesystems — &lt;code&gt;ReadWritePaths&lt;/code&gt; carves out the one directory Ollama needs to write models into, or pulls fail silently. Apply incrementally and check &lt;code&gt;systemctl status ollama&lt;/code&gt; after each addition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Ollama in Production Behind Nginx
&lt;/h2&gt;

&lt;p&gt;Ollama's FAQ gives the minimal baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:11434&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nf"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP-only, no access control. Leave &lt;code&gt;OLLAMA_HOST&lt;/code&gt; at its loopback default rather than binding to &lt;code&gt;0.0.0.0&lt;/code&gt; — nginx should be the only thing facing the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding TLS with Let's Encrypt
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-nginx
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;certbot rewrites the server block for HTTPS and installs a renewal timer automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Blocker: No Built-In Auth
&lt;/h2&gt;

&lt;p&gt;Every Ollama endpoint answers anyone who reaches the port. Auth has to live in nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$http_x_api_key&lt;/span&gt; &lt;span class="s"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"your-long-random-key-here")&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:11434&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nf"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;nginx's &lt;code&gt;if&lt;/code&gt; is unreliable for anything beyond one simple comparison — fine here, but don't stack more &lt;code&gt;if&lt;/code&gt; blocks expecting them to compose. For multiple keys, use &lt;code&gt;auth_request&lt;/code&gt; instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logs: journald, Not logrotate
&lt;/h2&gt;

&lt;p&gt;Ollama logs to journald by default — &lt;code&gt;logrotate&lt;/code&gt; doesn't apply. &lt;code&gt;journalctl -e -u ollama&lt;/code&gt; tails logs; retention is &lt;code&gt;/etc/systemd/journald.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Journal]&lt;/span&gt;
&lt;span class="py"&gt;SystemMaxUse&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;500M&lt;/span&gt;
&lt;span class="py"&gt;MaxRetentionSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1month&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set both — space caps alone let old quiet-period entries linger, age caps alone don't stop a sudden volume spike from filling disk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default systemd unit isn't sandboxed — add ProtectSystem=strict, PrivateTmp, NoNewPrivileges, ReadWritePaths&lt;/li&gt;
&lt;li&gt;Keep OLLAMA_HOST on loopback; nginx faces the network&lt;/li&gt;
&lt;li&gt;certbot --nginx handles TLS in two commands&lt;/li&gt;
&lt;li&gt;Zero built-in auth — an X-API-Key check in nginx is the minimum fix&lt;/li&gt;
&lt;li&gt;Logs go to journald, not a file — set SystemMaxUse and MaxRetentionSec instead of logrotate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full breakdown at &lt;a href="https://devtoolhub.com/ollama-production-vps-hardening/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ollama</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>security</category>
    </item>
    <item>
      <title>The terraform-docs GitHub Action: A Complete CI Setup Guide</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Fri, 18 Sep 2026 12:06:26 +0000</pubDate>
      <link>https://dev.to/amareswer/the-terraform-docs-github-action-a-complete-ci-setup-guide-2e3m</link>
      <guid>https://dev.to/amareswer/the-terraform-docs-github-action-a-complete-ci-setup-guide-2e3m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/terraform-docs-github-action/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://terraform-docs.io/how-to/github-action/" rel="noopener noreferrer"&gt;terraform-docs GitHub Action&lt;/a&gt; generates a Markdown table of every input, output, and variable in a Terraform module, then commits it straight into your &lt;code&gt;README.md&lt;/code&gt; on every pull request. The official docs page covers one example and stops there — no full input list, no config-file setup, and nothing about the one failure mode that catches almost everyone the first time they wire this into a real repo.&lt;/p&gt;

&lt;p&gt;This covers what the official page skips: every input the action actually supports, the difference between &lt;code&gt;fail-on-diff&lt;/code&gt; and auto-commit mode, how to document more than one module at once, and why the auto-commit step silently fails on pull requests from a fork.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the terraform-docs GitHub Action Actually Sets Up
&lt;/h2&gt;

&lt;p&gt;The action wraps the &lt;code&gt;terraform-docs&lt;/code&gt; CLI and runs it inside your workflow instead of on a developer's laptop. On a &lt;code&gt;pull_request&lt;/code&gt; trigger, it walks your &lt;code&gt;working-dir&lt;/code&gt;, generates the docs, and either prints them, replaces the target file, or injects them between two HTML comment markers in your existing &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That third mode — &lt;code&gt;output-method: inject&lt;/code&gt; — is the default, and it's the one worth understanding first. It looks for &lt;code&gt;&amp;lt;!-- BEGIN_TF_DOCS --&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;!-- END_TF_DOCS --&amp;gt;&lt;/code&gt; markers in the file. If they're there, the generated table replaces everything between them and leaves the rest of your README untouched. If the file doesn't have the markers yet, the action appends the generated block to the end. If the file doesn't exist at all, it creates one using the &lt;code&gt;template&lt;/code&gt; input, which must itself contain both markers or the next run has nowhere to inject into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every terraform-docs GitHub Action Input, Not Just the One in the Docs
&lt;/h2&gt;

&lt;p&gt;The official page's example sets four inputs and calls it done: &lt;code&gt;working-dir&lt;/code&gt;, &lt;code&gt;output-file&lt;/code&gt;, &lt;code&gt;output-method&lt;/code&gt;, &lt;code&gt;git-push&lt;/code&gt;. The action's actual README lists 18. Here's the full set:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;working-dir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Comma-separated list of directories to generate docs for&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output-file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File in the module directory where docs get written&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output-format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;markdown table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;terraform-docs output format (ignored if &lt;code&gt;config-file&lt;/code&gt; is set)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;print&lt;/code&gt;, &lt;code&gt;replace&lt;/code&gt;, or &lt;code&gt;inject&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;config-file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name of a terraform-docs config file to use instead of individual inputs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;atlantis-file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parse an Atlantis config to find module directories automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find-dir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a &lt;code&gt;find&lt;/code&gt; under this directory to discover &lt;code&gt;.tf&lt;/code&gt; files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;recursive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update submodules recursively instead of just &lt;code&gt;working-dir&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;recursive-path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Submodule path to walk when &lt;code&gt;recursive&lt;/code&gt; is true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fail-on-diff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fail the job if generated docs differ from what's committed (ignored if &lt;code&gt;git-push&lt;/code&gt; is set)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git-push&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commit and push the generated docs back to the branch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git-commit-message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;terraform-docs: automated action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commit message for the auto-push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;git-push-user-name&lt;/code&gt; / &lt;code&gt;git-push-user-email&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;empty&lt;/td&gt;
&lt;td&gt;Defaults to the &lt;code&gt;github-actions[bot]&lt;/code&gt; identity if left blank&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git-push-sign-off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a &lt;code&gt;Signed-off-by&lt;/code&gt; trailer to the commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;template&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTML comment markers&lt;/td&gt;
&lt;td&gt;Used only when &lt;code&gt;output-file&lt;/code&gt; doesn't already exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;indention&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Markdown heading indent level, 1 through 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;args&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extra flags passed straight through to the &lt;code&gt;terraform-docs&lt;/code&gt; binary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;fail-on-diff&lt;/code&gt; is explicitly ignored the moment &lt;code&gt;git-push&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;. And &lt;code&gt;output-format&lt;/code&gt; does nothing once you set &lt;code&gt;config-file&lt;/code&gt;, since the config file's own &lt;code&gt;formatter&lt;/code&gt; key takes over.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Auto-Commit Working: The checkout Step Most Setups Get Wrong
&lt;/h2&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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.head.ref }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without that &lt;code&gt;ref&lt;/code&gt; override, &lt;code&gt;actions/checkout&lt;/code&gt; defaults to a detached-HEAD merge commit — a synthetic ref GitHub builds to preview the merge. You can commit to it, but the commit goes nowhere real. Set &lt;code&gt;ref&lt;/code&gt; to &lt;code&gt;github.event.pull_request.head.ref&lt;/code&gt; and checkout lands on the actual PR branch.&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate terraform docs&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pull_request&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;docs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.head.ref }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform-docs/gh-actions@v1.4.1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;working-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;output-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;README.md&lt;/span&gt;
          &lt;span class="na"&gt;output-method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inject&lt;/span&gt;
          &lt;span class="na"&gt;git-push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;permissions: contents: write&lt;/code&gt; block isn't in the action's own examples, but you need it — some orgs default &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; to read-only, and the push fails before it even reaches the fork-specific problem below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why terraform-docs GitHub Action Fails on Forked Pull Requests
&lt;/h2&gt;

&lt;p&gt;GitHub's workflow-syntax docs are explicit: when a workflow runs on a &lt;code&gt;pull_request&lt;/code&gt; "from a forked repository," the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;'s "permissions are adjusted to change any write permissions to read only" — regardless of your &lt;code&gt;permissions:&lt;/code&gt; block. You "can use the &lt;code&gt;permissions&lt;/code&gt; key to add and remove read permissions for forked repositories, but typically you can't grant write access."&lt;/p&gt;

&lt;p&gt;Your workflow can have &lt;code&gt;contents: write&lt;/code&gt; right there in the YAML, &lt;code&gt;git-push&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;, and the checkout ref pointing at the exact right branch — none of it matters on a fork PR. The action generates the docs correctly, then fails on the push step with a 403.&lt;/p&gt;

&lt;p&gt;Two real workarounds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Switch to &lt;code&gt;fail-on-diff&lt;/code&gt; for external PRs&lt;/strong&gt; — you lose auto-commit, but the check still catches stale docs, and a human commits the fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;pull_request_target&lt;/code&gt; instead of &lt;code&gt;pull_request&lt;/code&gt;.&lt;/strong&gt; It grants a full read/write token on fork PRs, but runs in the base branch's context — never check out &lt;code&gt;head.ref&lt;/code&gt; from an untrusted fork with this event for anything beyond running &lt;code&gt;terraform-docs&lt;/code&gt; itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  fail-on-diff or Auto-Commit: Which Mode Should You Actually Use?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;fail-on-diff&lt;/code&gt; fails the job if the generated output doesn't match &lt;code&gt;README.md&lt;/code&gt; — nothing gets pushed, a human commits the fix. That's the safer default for a public or multi-contributor repo. Auto-commit (&lt;code&gt;git-push: true&lt;/code&gt;) fits an internal repo with a small trusted team, where a docs-bot commit is a fair trade for never having a stale README. Since the two are mutually exclusive on the same job, decide per repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documenting Every Module at Once
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;working-dir&lt;/code&gt; as a comma-separated list&lt;/strong&gt; (&lt;code&gt;working-dir: .,modules/vpc,modules/eks&lt;/code&gt;) works when you know every path already. &lt;strong&gt;&lt;code&gt;recursive: true&lt;/code&gt;&lt;/strong&gt; walks &lt;code&gt;recursive-path&lt;/code&gt; (default &lt;code&gt;modules&lt;/code&gt;) and picks up new submodules without touching the workflow file. &lt;strong&gt;&lt;code&gt;atlantis-file&lt;/code&gt;&lt;/strong&gt; reuses your existing &lt;code&gt;atlantis.yaml&lt;/code&gt; project list. &lt;strong&gt;&lt;code&gt;find-dir&lt;/code&gt;&lt;/strong&gt; runs a plain &lt;code&gt;find&lt;/code&gt; for &lt;code&gt;.tf&lt;/code&gt; files — the least structured option, useful with no fixed module convention yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a Config File Instead of Piling On Inputs
&lt;/h2&gt;

&lt;p&gt;Past four or five non-default inputs, a &lt;code&gt;.terraform-docs.yml&lt;/code&gt; is easier to manage than a wall of &lt;code&gt;with:&lt;/code&gt; keys:&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="na"&gt;formatter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;table"&lt;/span&gt;
&lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;README.md&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inject&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;&amp;lt;!-- BEGIN_TF_DOCS --&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;{{ .Content }}&lt;/span&gt;
    &lt;span class="s"&gt;&amp;lt;!-- END_TF_DOCS --&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;sort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;config-file: .terraform-docs.yml&lt;/code&gt; on the action, and &lt;code&gt;output-format&lt;/code&gt; stops doing anything — the config file's &lt;code&gt;formatter&lt;/code&gt; key wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;18 real inputs vs the 1 example shown on the official docs page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fail-on-diff&lt;/code&gt; and &lt;code&gt;git-push&lt;/code&gt; are mutually exclusive on the same job&lt;/li&gt;
&lt;li&gt;Auto-commit needs &lt;code&gt;ref: ${{ github.event.pull_request.head.ref }}&lt;/code&gt; on checkout&lt;/li&gt;
&lt;li&gt;Forked-repo PRs always get a read-only GITHUB_TOKEN — auto-commit silently fails there&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recursive&lt;/code&gt;, &lt;code&gt;atlantis-file&lt;/code&gt;, &lt;code&gt;find-dir&lt;/code&gt; cover three different multi-module layouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full breakdown at &lt;a href="https://devtoolhub.com/terraform-docs-github-action/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>githubactions</category>
      <category>devops</category>
      <category>cicd</category>
    </item>
    <item>
      <title>AI Agents Explained: How They Actually Work</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Thu, 17 Sep 2026 12:01:25 +0000</pubDate>
      <link>https://dev.to/amareswer/ai-agents-explained-how-they-actually-work-2c6d</link>
      <guid>https://dev.to/amareswer/ai-agents-explained-how-they-actually-work-2c6d</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/ai-agents-explained/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI agents explained in one sentence: software where an LLM decides what to do next — which tool to call, with what arguments — based on the result of what it just did, in a loop, instead of following a script you wrote in advance. That loop, and the model's control over it, is the entire difference between an agent and a regular app that happens to call an LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Agents Explained: What Makes Something an "Agent"?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.anthropic.com/engineering/building-effective-agents" rel="noopener noreferrer"&gt;Anthropic's own engineering team draws the line clearly&lt;/a&gt;. A workflow is a system "where LLMs and tools are orchestrated through predefined code paths." An agent is a system where "LLMs dynamically direct their own processes and tool usage, maintaining control over how they accomplish tasks." In a workflow, your code decides what happens next. In an agent, the model does — which tool to call, whether to call another after seeing the result, and when the task is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does an AI Agent Actually Call a Tool?
&lt;/h2&gt;

&lt;p&gt;Tool calling is a structured feature, not a prompt trick. You describe each tool as a JSON schema and pass it to the model. &lt;a href="https://github.com/ollama/ollama/blob/main/docs/api.md" rel="noopener noreferrer"&gt;Ollama's &lt;code&gt;/api/chat&lt;/code&gt;&lt;/a&gt; documents the shape: a &lt;code&gt;tools&lt;/code&gt; array with &lt;code&gt;type: "function"&lt;/code&gt; entries carrying a name, description, and parameters. When the model wants to use one, it returns a &lt;code&gt;tool_calls&lt;/code&gt; array with the function name and arguments — your code executes it and sends the real result back as a new message.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Agent Loop, and Why Does It Need a Stopping Condition?
&lt;/h2&gt;

&lt;p&gt;Observe state, decide an action, execute it, feed the result back as the new state. Left unchecked, that loop has no natural end. Anthropic's guidance is explicit that agent tasks "often terminate upon completion, but it's also common to include stopping conditions (such as a maximum number of iterations) to maintain control." Pick at least one before an agent goes near production traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Agents Explained: Where MCP Fits In
&lt;/h2&gt;

&lt;p&gt;Tool-calling JSON solves how a model requests a tool. It doesn't solve how an agent connects to tools it doesn't already know about — that's what MCP standardizes. See &lt;a href="https://devtoolhub.com/best-mcp-servers-by-category/" rel="noopener noreferrer"&gt;which MCP servers are worth connecting&lt;/a&gt; and &lt;a href="https://devtoolhub.com/mcp-server-authentication-spec-update/" rel="noopener noreferrer"&gt;what changed when MCP's auth spec updated&lt;/a&gt; before wiring an agent into one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI Agents Get Stuck in Loops
&lt;/h2&gt;

&lt;p&gt;A common failure isn't a wrong answer — it's the same tool call, same arguments, repeated forever, because "nothing in its setup tells it that repeating an identical call is pointless." Frameworks default to generous iteration caps (LangGraph 25 steps, LangChain 15) that catch this late. A no-progress guard — hash &lt;code&gt;(tool, arguments, result)&lt;/code&gt;, halt after 2-3 identical repeats — catches it in seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow or Agent?
&lt;/h2&gt;

&lt;p&gt;If the steps are known and fixed, build a workflow: more predictable, easier to debug, lower runaway-cost risk. Reach for an agent when the right sequence genuinely depends on what's discovered along the way. Most real systems mix both rather than making an entire pipeline agentic by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Vague tool success signals that invite retries. Trusting iteration limits alone to catch stuck loops fast. Skipping the tool-permission question — an agent is only as safe as what its tools can do. Making everything agentic when a fixed workflow would be simpler and cheaper.&lt;/p&gt;

&lt;p&gt;Full article with FAQ and quick summary: &lt;a href="https://devtoolhub.com/ai-agents-explained/" rel="noopener noreferrer"&gt;devtoolhub.com/ai-agents-explained&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>mcp</category>
    </item>
    <item>
      <title>What Is RAG? Retrieval-Augmented Generation Explained</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Tue, 15 Sep 2026 10:49:17 +0000</pubDate>
      <link>https://dev.to/amareswer/what-is-rag-retrieval-augmented-generation-explained-4afd</link>
      <guid>https://dev.to/amareswer/what-is-rag-retrieval-augmented-generation-explained-4afd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/what-is-rag/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is RAG, in one sentence? A way to make an LLM answer questions using documents it was never trained on, by searching those documents for relevant passages and handing the model the results as context before it generates a response. No retraining, no fine-tuning — just a search step bolted onto the front of a normal prompt.&lt;/p&gt;

&lt;p&gt;The term comes from a 2020 Facebook AI Research paper that described it as combining "pre-trained parametric and non-parametric memory for language generation" — the model's trained knowledge, plus a live lookup into an external index.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is RAG?
&lt;/h2&gt;

&lt;p&gt;Retrieval-augmented generation is a pattern, not a specific tool: retrieve relevant information for a query, then generate an answer using that information as context. &lt;a href="https://arxiv.org/abs/2005.11401" rel="noopener noreferrer"&gt;The original RAG paper&lt;/a&gt;, authored by Patrick Lewis and colleagues at Facebook AI Research, paired a pre-trained sequence-to-sequence model with a dense vector index accessed by a pre-trained neural retriever.&lt;/p&gt;

&lt;p&gt;RAG exists because LLMs have two hard limits. Their knowledge is frozen at training time, and they don't know your private data at all. Retrieval solves both by pulling relevant text in at request time instead of baking it into the weights.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is RAG Actually Doing When It Retrieves Data?
&lt;/h2&gt;

&lt;p&gt;The pipeline runs a fixed sequence for every question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Chunk your documents into smaller passages&lt;/li&gt;
&lt;li&gt;Embed each chunk into a vector using an embedding model&lt;/li&gt;
&lt;li&gt;Store the vectors in a vector database&lt;/li&gt;
&lt;li&gt;Embed the incoming question the same way&lt;/li&gt;
&lt;li&gt;Retrieve the chunks whose vectors are closest to the question&lt;/li&gt;
&lt;li&gt;Generate an answer using those chunks as context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Any LLM can handle the generation step. The retrieval half is what makes RAG RAG.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Vector Database, and Why Does RAG Need One?
&lt;/h2&gt;

&lt;p&gt;A vector database indexes by geometric closeness rather than exact values, so a search for "how do I reset a password" can match "forgot your login credentials" even with almost no word overlap. &lt;a href="https://github.com/ollama/ollama/blob/main/docs/api.md" rel="noopener noreferrer"&gt;Ollama's API&lt;/a&gt; exposes &lt;code&gt;/api/embed&lt;/code&gt; for this: send &lt;code&gt;{"model": "...", "input": "..."}&lt;/code&gt;, get back an array of floats per input. &lt;a href="https://ollama.com/library/nomic-embed-text" rel="noopener noreferrer"&gt;&lt;code&gt;nomic-embed-text&lt;/code&gt;&lt;/a&gt; is a solid local default — Ollama's own listing states it beats OpenAI's &lt;code&gt;text-embedding-ada-002&lt;/code&gt; and &lt;code&gt;text-embedding-3-small&lt;/code&gt; on short and long context tasks, at a 274MB download.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why More Retrieved Chunks Doesn't Mean Better Answers
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://arxiv.org/abs/2307.03172" rel="noopener noreferrer"&gt;2023 Stanford/Berkeley/Samaya AI study&lt;/a&gt; found model performance "is often highest when relevant information occurs at the beginning or end of the input context" and "significantly degrades" when it's buried in the middle — the "lost in the middle" effect. A tighter retrieval step of 3-5 genuinely relevant, well-ranked chunks tends to outperform a looser one with more, worse-ranked results.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG vs Fine-Tuning
&lt;/h2&gt;

&lt;p&gt;RAG adds new knowledge without touching the model's weights — good for data that changes. Fine-tuning changes model behavior, tone, or output format by retraining the weights. They solve different problems and plenty of production systems use both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Chunking without testing retrieval quality. Assuming the retriever always finds something relevant (it doesn't stop hallucination, it just changes what gets hallucinated on top of). Skipping re-indexing after data changes. Treating every task as a RAG problem when the answer already lives in the model's training data.&lt;/p&gt;

&lt;p&gt;Full article with the FAQ and quick summary: &lt;a href="https://devtoolhub.com/what-is-rag/" rel="noopener noreferrer"&gt;devtoolhub.com/what-is-rag&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>ollama</category>
    </item>
    <item>
      <title>What Is an LLM? A Working Model for Engineers</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Mon, 14 Sep 2026 11:46:39 +0000</pubDate>
      <link>https://dev.to/amareswer/what-is-an-llm-a-working-model-for-engineers-24pd</link>
      <guid>https://dev.to/amareswer/what-is-an-llm-a-working-model-for-engineers-24pd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/what-is-an-llm/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An LLM is a model that has one job: given the text so far, predict the next token, append it, and repeat. That's it. Everything else — chat interfaces, coding assistants, agents that call tools — is scaffolding built around that one loop running thousands of times per response.&lt;/p&gt;

&lt;p&gt;Most explanations either stop at "it's trained on the internet" or jump straight into transformer math you'll never touch. Neither one helps when you're deciding how much VRAM to buy, why a long conversation suddenly gets dumber, or why your token bill doubled overnight. This is the model you actually need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an LLM?
&lt;/h2&gt;

&lt;p&gt;A large language model is a neural network trained to predict the next token in a sequence, repeated over enough text that it picks up grammar, facts, and reasoning patterns as a side effect of getting good at that one task. Hugging Face's own generation docs put it plainly: an LLM "is trained to generate the next word (token) given some initial text (prompt) along with its own generated outputs up to a predefined length or when it reaches an end-of-sequence (&lt;code&gt;EOS&lt;/code&gt;) token."&lt;/p&gt;

&lt;p&gt;That's the whole mechanism. There's no separate "understanding" step. The model has learned, from its training data, which token is statistically likely to come next given everything before it — and at large enough scale, "statistically likely" starts looking a lot like reasoning.&lt;/p&gt;

&lt;p&gt;Size is measured in &lt;strong&gt;parameters&lt;/strong&gt; — the numeric weights the network adjusts during training. A 7B model has about 7 billion of them. More parameters generally means better output, but it also means more memory to hold the weights and more compute per token generated. That trade-off is the entire reason quantized, smaller models exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does an LLM generate text?
&lt;/h2&gt;

&lt;p&gt;One token at a time, in a loop, with no ability to revise what it already wrote. The model looks at every token so far — your prompt plus whatever it has generated in this response. Then it outputs a probability distribution over its entire vocabulary for what comes next.&lt;/p&gt;

&lt;p&gt;Then a decoding strategy picks the actual token from that distribution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Greedy search&lt;/strong&gt; — always pick the single most likely next token. This is the library's default decoding strategy. Deterministic, and prone to repetitive output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sampling&lt;/strong&gt; — pick randomly from the distribution, weighted by probability, controlled by a temperature parameter. Low temperature (under 0.4) stays close to greedy; high temperature (above 0.8) gets more varied and more prone to nonsense.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That picked token gets appended to the sequence, and the whole thing runs again to pick the next one. This continues until the model emits an end-of-sequence token or hits a length limit you set. There is no lookahead and no backtracking — once a token is chosen, it's part of the context for every token that follows, mistakes included.&lt;/p&gt;

&lt;p&gt;This is also why LLMs hallucinate confidently instead of saying "I don't know." The model isn't checking facts; it's continuing a pattern. If the highest-probability continuation of a plausible-sounding sentence is a wrong fact, the model produces the wrong fact with the same fluency as a right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a token, and why does the context window matter?
&lt;/h2&gt;

&lt;p&gt;A token is the model's actual unit of work — usually a word, part of a word, or a punctuation mark, not a full sentence. "Deployment" might be one token; "unconfigured" often splits into two or three. Everything you feed the model and everything it generates gets converted to and from tokens.&lt;/p&gt;

&lt;p&gt;The context window is the maximum number of tokens the model can hold in memory at once — your system prompt, the conversation history, and the response it's generating, all counted together. Run out of room and the oldest tokens get dropped or the request fails outright, depending on how the client handles it.&lt;/p&gt;

&lt;p&gt;This is a hard ceiling, not a soft one. A model with a 4,096-token context window doesn't get slower as you approach the limit — it silently loses the beginning of the conversation, or errors out, depending on the client.&lt;/p&gt;

&lt;p&gt;Context windows vary by model and by how you run it — Ollama's own docs aren't fully consistent on the default either. Its FAQ quotes a flat "4096 tokens," but the newer context-length docs say the real default scales with GPU VRAM: 4k below 24 GiB, 32k from 24–48 GiB, 256k at 48 GiB and up. Check &lt;code&gt;num_ctx&lt;/code&gt; or &lt;code&gt;ollama show &amp;lt;model&amp;gt;&lt;/code&gt; rather than assuming — see DevToolHub's &lt;a href="https://devtoolhub.com/ollama-hardware-requirements/" rel="noopener noreferrer"&gt;Ollama hardware requirements guide&lt;/a&gt; for how much RAM and VRAM that adds per model size.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to measure your LLM's token throughput yourself
&lt;/h2&gt;

&lt;p&gt;Run any local model with the verbose flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run llama3.1 &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="s2"&gt;"Explain quicksort in one paragraph"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output includes a full timing breakdown, including &lt;code&gt;prompt eval rate&lt;/code&gt; and &lt;code&gt;eval rate&lt;/code&gt; in tokens per second. &lt;code&gt;eval rate&lt;/code&gt; is the number that actually determines whether a chat feels instant or sluggish. Ollama's API returns the same data as raw fields on every call — &lt;code&gt;prompt_eval_count&lt;/code&gt;, &lt;code&gt;eval_count&lt;/code&gt;, &lt;code&gt;prompt_eval_duration&lt;/code&gt;, &lt;code&gt;eval_duration&lt;/code&gt;, all in nanoseconds — so you can calculate tokens per second yourself with &lt;code&gt;eval_count / eval_duration * 10^9&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why model size and quantization determine your hardware
&lt;/h2&gt;

&lt;p&gt;A 70B model outperforms a 7B model on complex reasoning, but needs roughly 8x the memory and runs far fewer tokens per second on the same GPU. For narrow tasks — classification, extraction, simple chat — a well-chosen 7B or 12B model often gets you most of the quality at a fraction of the cost.&lt;/p&gt;

&lt;p&gt;Quantization shrinks memory footprint by reducing weight precision — from 16-bit down to 4-bit, typically — cutting model size roughly 4x with a modest quality loss. That's why an 8B model tagged &lt;code&gt;Q4_K_M&lt;/code&gt; downloads at around 5 GB instead of the 16+ GB its full-precision weights would take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes engineers make with LLMs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treating a bigger model as always the right call.&lt;/strong&gt; For narrow tasks, a smaller tuned model often matches a frontier model's accuracy at a fraction of the latency and cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not budgeting for context growth.&lt;/strong&gt; A tool-calling agent can burn through thousands of tokens before producing one user-facing answer — every tool description and response counts against the same context window as the conversation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming greedy decoding is always safe.&lt;/strong&gt; It's deterministic, which helps testing, but makes output more repetitive and prone to looping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping the auth model on tool-calling setups.&lt;/strong&gt; An LLM that can call tools is only as safe as what those tools are allowed to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full article with the FAQ and quick summary: &lt;a href="https://devtoolhub.com/what-is-an-llm/" rel="noopener noreferrer"&gt;devtoolhub.com/what-is-an-llm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>ollama</category>
    </item>
    <item>
      <title>The MCP Registry, By the Numbers</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Fri, 11 Sep 2026 12:08:01 +0000</pubDate>
      <link>https://dev.to/amareswer/the-mcp-registry-by-the-numbers-38nc</link>
      <guid>https://dev.to/amareswer/the-mcp-registry-by-the-numbers-38nc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/mcp-registry-by-the-numbers/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://modelcontextprotocol.io/registry/about" rel="noopener noreferrer"&gt;official MCP registry&lt;/a&gt; is the closest thing the Model Context Protocol has to an app store. So we pulled every entry from its API and counted what's actually in there. The short version: &lt;strong&gt;30,375 servers as of September 10, 2026, but a third of them come from about 50 accounts, 62% were published once and never updated, and the companies that founded MCP have published almost none of their own servers there.&lt;/strong&gt; The registry changes every hour, so treat these as a snapshot, not a leaderboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  How big the MCP registry actually is
&lt;/h2&gt;

&lt;p&gt;The registry API returned &lt;strong&gt;99,114 server-and-version records&lt;/strong&gt;, which collapse to &lt;strong&gt;30,375 unique servers&lt;/strong&gt; once you keep only the latest version of each. That is roughly 3x what it held in May 2026 (about 9,650 servers), and the curve is still steepening:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Month servers first published&lt;/th&gt;
&lt;th&gt;New servers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sep 2025 (launch)&lt;/td&gt;
&lt;td&gt;407&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feb 2026&lt;/td&gt;
&lt;td&gt;1,081&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apr 2026&lt;/td&gt;
&lt;td&gt;2,387&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jun 2026&lt;/td&gt;
&lt;td&gt;3,662&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jul 2026&lt;/td&gt;
&lt;td&gt;4,840&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aug 2026&lt;/td&gt;
&lt;td&gt;6,265&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;August 2026 alone added more servers than the registry's entire first five months combined. Whatever "MCP adoption" means, the supply side is not the bottleneck.&lt;/p&gt;

&lt;p&gt;Almost nothing ever leaves. Of the 30,375 servers, &lt;strong&gt;98.9% are marked active and 1.1% (332) are deprecated&lt;/strong&gt;. Zero are visibly deleted. The registry adds; it does not prune.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is publishing all these servers
&lt;/h2&gt;

&lt;p&gt;Every server name is a reverse-DNS namespace tied to a verified source — either a GitHub account (&lt;code&gt;io.github.username/server&lt;/code&gt;) or a domain the publisher proved they own (&lt;code&gt;com.example/server&lt;/code&gt;), per the &lt;a href="https://github.com/modelcontextprotocol/registry" rel="noopener noreferrer"&gt;registry's publishing rules&lt;/a&gt;. The split:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;67.2% published under an &lt;code&gt;io.github.*&lt;/code&gt; namespace&lt;/strong&gt; — an individual or org GitHub account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;32.8% published under a verified domain&lt;/strong&gt; — companies with &lt;code&gt;com.&lt;/code&gt;, &lt;code&gt;io.&lt;/code&gt;, &lt;code&gt;ai.&lt;/code&gt;, &lt;code&gt;dev.&lt;/code&gt; prefixes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Across ~18,200 distinct publishers, the distribution is extremely top-heavy. &lt;strong&gt;The top 10 publishers account for 17.7% of every server in the registry. The top 50 account for 24.6%.&lt;/strong&gt; Meanwhile 16,356 publishers have exactly one server each.&lt;/p&gt;

&lt;p&gt;The largest single publisher, &lt;code&gt;io.github.sadri-dridi&lt;/code&gt;, has &lt;strong&gt;1,505 servers&lt;/strong&gt; — about one in every twenty in the registry. They are single-function micro-tools with descriptions like "Acres to hectares, number discarded" and "Absolute value sign, number discarded." The next tier tells a similar story: &lt;code&gt;io.github.Evozim&lt;/code&gt; has 375 servers, and 276 registry entries share the exact description "Premium agentic endpoint for [name]-mcp." &lt;code&gt;ai.smithery&lt;/code&gt; mirrored 213 servers straight from its own directory, test projects and all.&lt;/p&gt;

&lt;p&gt;Some bulk publishers are doing real work — &lt;code&gt;io.github.pipeworx-io&lt;/code&gt; (1,321 servers) and &lt;code&gt;io.github.mcp-dir&lt;/code&gt; (1,113) are systematically wrapping public APIs with genuine descriptions. But the pattern holds: the raw server count is inflated by a handful of automated publishing operations, not 30,000 hand-built tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remote won: how MCP servers are actually deployed
&lt;/h2&gt;

&lt;p&gt;Every server declares how you connect to it — a remote HTTP endpoint, a local package you install, or both.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Deployment&lt;/th&gt;
&lt;th&gt;Share of servers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remote only (HTTP / SSE)&lt;/td&gt;
&lt;td&gt;54.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local only (installable package)&lt;/td&gt;
&lt;td&gt;38.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Both&lt;/td&gt;
&lt;td&gt;4.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neither declared&lt;/td&gt;
&lt;td&gt;1.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Remote is now the majority, and it's overwhelmingly the current transport: &lt;strong&gt;17,584 remote endpoints use &lt;code&gt;streamable-http&lt;/code&gt; versus 1,073 still on the deprecated &lt;code&gt;sse&lt;/code&gt;&lt;/strong&gt; transport.&lt;/p&gt;

&lt;p&gt;For the local servers, the package ecosystem breaks down as:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package registry&lt;/th&gt;
&lt;th&gt;Packages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;8,673&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyPI&lt;/td&gt;
&lt;td&gt;3,684&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mcpb (Claude Desktop bundle)&lt;/td&gt;
&lt;td&gt;1,158&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCI (container image)&lt;/td&gt;
&lt;td&gt;899&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NuGet&lt;/td&gt;
&lt;td&gt;111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cargo&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;npm is more than twice PyPI. If you maintain MCP tooling, that's where the users are.&lt;/p&gt;

&lt;h2&gt;
  
  
  The maintenance problem
&lt;/h2&gt;

&lt;p&gt;Here's the number that should make you cautious about picking a server off the list by its description alone.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;62% of servers have exactly one published version.&lt;/strong&gt; They shipped once and were never revised.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;40.8% of servers' latest version is still &lt;code&gt;1.0.0&lt;/code&gt;, &lt;code&gt;0.1.0&lt;/code&gt;, or &lt;code&gt;0.0.1&lt;/code&gt;&lt;/strong&gt; — a first release with no iteration behind it.&lt;/li&gt;
&lt;li&gt;Median versions per server: &lt;strong&gt;1&lt;/strong&gt;. The mean is 3.26 only because a few servers have hundreds of releases (the busiest has 1,176).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On freshness, the picture is better than the versioning suggests but still uneven. Grouping every server by when its current version was last updated:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Last updated&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;Within 30 days&lt;/td&gt;
&lt;td&gt;37.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31–90 days&lt;/td&gt;
&lt;td&gt;25.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;91–180 days&lt;/td&gt;
&lt;td&gt;19.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;181–365 days&lt;/td&gt;
&lt;td&gt;7.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No update timestamp&lt;/td&gt;
&lt;td&gt;9.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Roughly &lt;strong&gt;36% of servers haven't been touched in three months or more&lt;/strong&gt; (counting the ones with no timestamp). For a protocol whose auth and transport spec changed materially in the &lt;a href="https://devtoolhub.com/mcp-server-authentication-spec-update/" rel="noopener noreferrer"&gt;2026-07-28 update&lt;/a&gt;, a server last updated in early 2026 is a server that predates the current rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the registry does not tell you
&lt;/h2&gt;

&lt;p&gt;The registry entry for a server records its name, description, version, transport type, the package or remote URL, a link to the source repository, icons, and a website. That is the whole schema.&lt;/p&gt;

&lt;p&gt;It records &lt;strong&gt;nothing about whether the server is safe to run.&lt;/strong&gt; There is no field for the authentication method, no security-review status, no check that the remote endpoint is even online, and no install or usage count. Namespace verification proves the &lt;em&gt;publisher&lt;/em&gt; controls &lt;code&gt;io.github.their-account&lt;/code&gt; — it says nothing about the server behind it.&lt;/p&gt;

&lt;p&gt;And &lt;strong&gt;22.9% of servers link no source repository at all.&lt;/strong&gt; For remote-only servers — the ones you point an agent at over HTTP — that rises to &lt;strong&gt;37%&lt;/strong&gt;. More than a third of the remote MCP servers in the official registry give you an endpoint and a description, and no code to read.&lt;/p&gt;

&lt;p&gt;This matters because "official registry" carries weight it hasn't earned yet. It's official in the sense that the &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;MCP project&lt;/a&gt; runs it — not in the sense that anything in it is vetted. The &lt;a href="https://devtoolhub.com/best-mcp-servers-by-category/" rel="noopener noreferrer"&gt;archived reference Postgres server with a read-only bypass&lt;/a&gt; is the reminder: a trusted label is not an audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The founding vendors have barely shown up
&lt;/h2&gt;

&lt;p&gt;The registry is backed by Anthropic, GitHub, and Microsoft. Their own server counts in it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Namespace&lt;/th&gt;
&lt;th&gt;Servers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;com.microsoft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;io.github.github&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;com.stripe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;io.github.awslabs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;com.anthropic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;io.github.modelcontextprotocol&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The official reference servers, GitHub's remote MCP server, Anthropic's own tools — most of the servers you'd actually reach for aren't published to the registry their maintainers built. Discovery for the servers that matter still happens through docs and word of mouth, not the registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually use the MCP registry
&lt;/h2&gt;

&lt;p&gt;It's a genuinely useful index for one thing: &lt;strong&gt;finding out whether a server exists and where its code lives.&lt;/strong&gt; Beyond that, filter hard.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start from the namespace.&lt;/strong&gt; A &lt;code&gt;com.&lt;/code&gt; or &lt;code&gt;io.&lt;/code&gt; verified-domain namespace means a company staked its domain on it. An &lt;code&gt;io.github.&lt;/code&gt; namespace with 1,000+ servers under it is a bulk operation — judge the individual server, not the publisher.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the version and the update date, not just the description.&lt;/strong&gt; &lt;code&gt;1.0.0&lt;/code&gt;, published eight months ago, no repo link — skip it, especially for anything remote.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow the repository link before you connect anything.&lt;/strong&gt; If there isn't one, and it's a remote server, that's a hard stop for production use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-verify auth yourself.&lt;/strong&gt; The registry won't tell you if a remote server implements the current OAuth 2.1 requirement. You still have to check each one against its own docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: How many MCP servers are in the official registry?&lt;/strong&gt;&lt;br&gt;
A: 30,375 unique servers as of September 10, 2026, from about 99,000 total version records. It has roughly tripled since May 2026 and is still growing, adding more than 6,000 new servers in August 2026 alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Are the servers in the MCP registry vetted or secure?&lt;/strong&gt;&lt;br&gt;
A: No. The registry verifies that a publisher owns the namespace they publish under (via GitHub OAuth or domain verification), but it stores no security review, no authentication details, and no check that a server works. Treat a listing as "this exists," not "this is safe."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is the official MCP registry the biggest one?&lt;/strong&gt;&lt;br&gt;
A: It's the canonical one, but not the only index. Third-party directories like PulseMCP and Smithery aggregate across sources and report similar or larger totals depending on how they count. Some of the official registry's volume is mirrored from those directories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Should I publish my MCP server to the registry?&lt;/strong&gt;&lt;br&gt;
A: Yes, if it's real and maintained — it's free, and it's where automated discovery is heading. Publish under a verified-domain namespace if you can, link the source repository, and keep the version current with the spec. That alone puts you ahead of most of the list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Why aren't Anthropic's or GitHub's servers in the registry?&lt;/strong&gt;&lt;br&gt;
A: Unclear. As of this snapshot, &lt;code&gt;com.anthropic&lt;/code&gt; has zero entries and &lt;code&gt;io.github.github&lt;/code&gt; has one. The founding organizations built the registry but have mostly not populated it with their own servers, so the highest-quality servers are underrepresented.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The official MCP registry holds 30,375 servers (99,114 version records) as of 2026-09-10, up ~3x since May 2026, adding 6,000+ per month&lt;/li&gt;
&lt;li&gt;67% are published under a personal GitHub namespace; the top 10 publishers account for 17.7% of all servers, one of them with 1,505 single-function micro-tools&lt;/li&gt;
&lt;li&gt;55% of servers are remote-only (almost all &lt;code&gt;streamable-http&lt;/code&gt;), 39% are local packages (npm leads, then PyPI, then Claude Desktop bundles)&lt;/li&gt;
&lt;li&gt;62% have only one version, 41% are still on a &lt;code&gt;1.0.x&lt;/code&gt;/&lt;code&gt;0.x&lt;/code&gt; first release, and ~36% haven't been updated in 3+ months&lt;/li&gt;
&lt;li&gt;The registry records no auth method, no security review, and no uptime check; 23% of servers (37% of remote-only ones) link no source repository&lt;/li&gt;
&lt;li&gt;Anthropic, GitHub, and Microsoft — who back the registry — have published almost none of their own servers to it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The registry is a directory, not a seal of approval. Use it to find servers and their code, then vet each one the way you'd vet any dependency you're about to hand your data to.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>modelcontextprotocol</category>
      <category>aiagents</category>
      <category>aitools</category>
    </item>
    <item>
      <title>Best MCP Servers in 2026: One Pick Per Category</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Thu, 10 Sep 2026 12:14:14 +0000</pubDate>
      <link>https://dev.to/amareswer/best-mcp-servers-in-2026-one-pick-per-category-1mdg</link>
      <guid>https://dev.to/amareswer/best-mcp-servers-in-2026-one-pick-per-category-1mdg</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/best-mcp-servers-by-category/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The best MCP servers in 2026 aren't just the ones with the most GitHub stars. With the &lt;a href="https://devtoolhub.com/mcp-server-authentication-spec-update/" rel="noopener noreferrer"&gt;2026-07-28 spec update&lt;/a&gt; — final and current since late July — making OAuth 2.1 mandatory for every remote MCP server, "best" now also means "still working under the final spec." Here's one solid pick per category, what it actually does, and where it stands on auth.&lt;/p&gt;

&lt;p&gt;This is for anyone deploying MCP servers for a team, not just testing one locally. If you're only running servers on your own machine for personal use, the OAuth requirement mostly doesn't touch you — skip to the core utilities section below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes the Best MCP Servers in 2026
&lt;/h2&gt;

&lt;p&gt;Three things separate a server worth deploying from one that'll cause you problems in six months:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Who maintains it&lt;/strong&gt; — official vendor support beats an abandoned community fork&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's deployed&lt;/strong&gt; — local/stdio servers never needed OAuth; remote/HTTP servers now do&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whether it's actually been tested against real attacks&lt;/strong&gt; — not every "official" label means safe, as you'll see below&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best MCP Servers by Category
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Maintainer&lt;/th&gt;
&lt;th&gt;Transport&lt;/th&gt;
&lt;th&gt;OAuth Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core utilities&lt;/td&gt;
&lt;td&gt;Filesystem, Git, Fetch, Memory&lt;/td&gt;
&lt;td&gt;MCP steering group&lt;/td&gt;
&lt;td&gt;Local (stdio)&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev/code&lt;/td&gt;
&lt;td&gt;GitHub MCP Server&lt;/td&gt;
&lt;td&gt;GitHub (official)&lt;/td&gt;
&lt;td&gt;Remote (also local)&lt;/td&gt;
&lt;td&gt;OAuth 2.1 + PKCE, GA since Sept 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;Stripe MCP Server&lt;/td&gt;
&lt;td&gt;Stripe (official)&lt;/td&gt;
&lt;td&gt;Remote hosted (local stdio also available)&lt;/td&gt;
&lt;td&gt;OAuth by default; docs still cite the pre-2026 MCP auth spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Sentry MCP Server&lt;/td&gt;
&lt;td&gt;Sentry (official)&lt;/td&gt;
&lt;td&gt;Remote (hosted on Cloudflare; local stdio available)&lt;/td&gt;
&lt;td&gt;OAuth via your Sentry org login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docs/productivity&lt;/td&gt;
&lt;td&gt;Notion MCP Server&lt;/td&gt;
&lt;td&gt;Notion (official)&lt;/td&gt;
&lt;td&gt;Remote hosted (official local server exists)&lt;/td&gt;
&lt;td&gt;OAuth on hosted; token-based on local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Databases&lt;/td&gt;
&lt;td&gt;Postgres (community forks)&lt;/td&gt;
&lt;td&gt;Community (official version archived)&lt;/td&gt;
&lt;td&gt;Local (stdio)&lt;/td&gt;
&lt;td&gt;Not applicable, but read the warning below&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Core Utilities: No OAuth Needed Here
&lt;/h2&gt;

&lt;p&gt;The official reference servers — Filesystem, Fetch, Git, Memory, Sequential Thinking, and Time — are maintained directly by the MCP steering group. They run locally over stdio. That means they never talk to the network in the first place. The 2026-07-28 auth overhaul doesn't touch them, because the OAuth requirement applies to remote transports only.&lt;/p&gt;

&lt;p&gt;If your agent just needs to read local files, search git history, or fetch a URL, these cover it. No auth setup required. That's also their limit — nothing here is shareable across a team the way a hosted server is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remote Servers with OAuth Already Built In
&lt;/h2&gt;

&lt;p&gt;Three vendors got ahead of the auth shift instead of scrambling after the spec finalized — with one caveat worth knowing on compliance claims.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt; shipped its remote MCP server to general availability in September 2025. It's the only one of the three that explicitly documents OAuth 2.1 with PKCE, across VS Code, Visual Studio, JetBrains, Eclipse, Xcode, and Cursor. Short-lived, auto-refreshing credentials replace long-lived personal access tokens — exactly the direction the final spec pushes every server toward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stripe&lt;/strong&gt; runs its primary MCP server as a hosted endpoint at &lt;code&gt;mcp.stripe.com&lt;/code&gt;, with &lt;a href="https://docs.stripe.com/mcp" rel="noopener noreferrer"&gt;OAuth as the default&lt;/a&gt; and restricted API keys available for autonomous agents that need a narrower blast radius than a full secret key. A local stdio option also exists (&lt;code&gt;@stripe/mcp&lt;/code&gt; on npm, still actively updated) for anyone who'd rather keep keys off a hosted flow. One honest caveat: Stripe's docs still reference the pre-2026 MCP authorization spec, so verify its 2026-07-28 alignment yourself before treating it as fully compliant with the new requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentry&lt;/strong&gt; took the hosted-first path, running its server on Cloudflare's Workers platform with &lt;a href="https://blog.sentry.io/yes-sentry-has-an-mcp-server-and-its-pretty-good/" rel="noopener noreferrer"&gt;OAuth tied to your existing Sentry organization login&lt;/a&gt;. Sentry's own writeup is blunt about why hosted comes first: the local install workflow — cloning repos, managing config paths — has "a lot of sharp edges." A local stdio mode still exists for those who want it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notion&lt;/strong&gt;'s hosted MCP server is OAuth-based and the path Notion recommends. An official local stdio server (&lt;a href="https://github.com/makenotion/notion-mcp-server" rel="noopener noreferrer"&gt;notion-mcp-server&lt;/a&gt;) authenticated with an internal integration token still exists too, though Notion has flagged it may be sunset — build new integrations against the hosted endpoint.&lt;/p&gt;

&lt;p&gt;[IMAGE: articles/images/2026-07-25-best-mcp-servers-by-category-diagram.png | alt: "local vs remote MCP servers and which ones need OAuth 2.1"]&lt;/p&gt;

&lt;h2&gt;
  
  
  The Postgres Warning: Official Doesn't Mean Safe
&lt;/h2&gt;

&lt;p&gt;Here's the one every other "best MCP servers" list skips. Anthropic's own reference Postgres server shipped a read-only mode meant to block writes. It didn't. &lt;a href="https://securitylabs.datadoghq.com/articles/mcp-vulnerability-case-study-SQL-injection-in-the-postgresql-mcp-server/" rel="noopener noreferrer"&gt;Datadog Security Labs' case study&lt;/a&gt; documents the SQL injection in detail: the server happily accepted a semicolon-delimited &lt;code&gt;COMMIT; DROP SCHEMA public CASCADE;&lt;/code&gt; — breaking straight out of its own read-only transaction. Worth being precise about the timeline: the server was archived in May 2025 as part of a bulk sweep of unmaintained reference servers, and the security disclosure landed after — on a server that was already abandoned. Nobody was watching it either way.&lt;/p&gt;

&lt;p&gt;The lesson isn't "avoid database MCP servers." It's that a vendor's name on a server doesn't guarantee its safety claims hold up. If you're running a Postgres MCP server today, use a community fork with real query parsing and permission attenuation. Confirm it's still maintained before you trust it with production credentials — the same instinct you'd bring to any &lt;a href="https://devtoolhub.com/falco-kubernetes-runtime-security/" rel="noopener noreferrer"&gt;runtime security tooling&lt;/a&gt; that promises to enforce a boundary it hasn't actually tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Best MCP Servers for Your Stack
&lt;/h2&gt;

&lt;p&gt;Match the deployment model to who's using it, not just what the server does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Solo use, local machine&lt;/strong&gt; — stick with core utilities and local stdio servers. No OAuth to configure, nothing exposed to the network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared across a team, low-sensitivity data&lt;/strong&gt; — remote servers like GitHub, Stripe, or Sentry are built for this. All three run OAuth-first; GitHub documents OAuth 2.1 + PKCE explicitly, and for the others, verify current 2026-07-28 spec alignment against their docs before you rely on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive internal data (databases, internal APIs)&lt;/strong&gt; — self-host, and don't assume "official" means "audited." Check the maintenance history yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building any of this out as part of a Claude-based workflow, &lt;a href="https://devtoolhub.com/anthropic-academy-free-claude-courses/" rel="noopener noreferrer"&gt;Anthropic's developer training track&lt;/a&gt; covers MCP server setup directly, alongside Agent Skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Do I need OAuth for a local MCP server I only run on my own machine?&lt;/strong&gt;&lt;br&gt;
A: No. The OAuth 2.1 requirement in the 2026-07-28 spec applies to remote/HTTP transports. A local stdio server never exposed itself to the network, so it isn't in scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is the official Anthropic Postgres MCP server still usable?&lt;/strong&gt;&lt;br&gt;
A: It's archived and unmaintained — it went into Anthropic's archive sweep in May 2025, and a real read-only bypass was disclosed after that. Use one of the actively maintained community forks instead, and verify its query-parsing approach before connecting production credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Which MCP server should a small team deploy first?&lt;/strong&gt;&lt;br&gt;
A: Start with whichever remote server you already pay for and trust. GitHub, Stripe, and Sentry are all officially maintained and OAuth-first. Each one solves a real, specific problem instead of acting as a general-purpose demo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Are community MCP servers safe to use in production?&lt;/strong&gt;&lt;br&gt;
A: Some are. Check who maintains it, when they last updated it, and whether anyone has reviewed it for the same class of bug that took down the official Postgres server. An unaudited read-only claim is not the same as an enforced one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The best MCP servers for most teams split cleanly by transport: core utilities (Filesystem, Git, Fetch, Memory) run locally over stdio and don't need OAuth at all&lt;/li&gt;
&lt;li&gt;GitHub's remote MCP server documents OAuth 2.1 + PKCE explicitly; Stripe and Sentry ship OAuth-first hosted servers (Stripe's docs still cite the pre-2026 auth spec — verify before assuming full compliance)&lt;/li&gt;
&lt;li&gt;Stripe's hosted endpoint is the primary path, but an official local stdio server (&lt;code&gt;@stripe/mcp&lt;/code&gt;) exists too&lt;/li&gt;
&lt;li&gt;Anthropic's reference Postgres server — archived as unmaintained in May 2025 — had a read-only mode that failed to block a &lt;code&gt;DROP SCHEMA&lt;/code&gt; statement, per Datadog Security Labs&lt;/li&gt;
&lt;li&gt;Match server deployment to sensitivity: local for anything internal, remote OAuth servers for shared team tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Audit which of the best MCP servers your team already runs against this list — the 2026-07-28 spec is final, so any remote server not yet aligned with its OAuth requirements is the one to fix before older clients start failing against it.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>modelcontextprotocol</category>
      <category>aiagents</category>
      <category>oauth</category>
    </item>
    <item>
      <title>MCP Server Authentication: What the 2026-07-28 Spec Broke</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Thu, 10 Sep 2026 01:31:37 +0000</pubDate>
      <link>https://dev.to/amareswer/mcp-server-authentication-what-the-2026-07-28-spec-broke-4lfa</link>
      <guid>https://dev.to/amareswer/mcp-server-authentication-what-the-2026-07-28-spec-broke-4lfa</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/mcp-server-authentication-spec-update/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;MCP server authentication stopped being optional a month ago. The Model Context Protocol's largest spec revision since launch &lt;a href="https://blog.modelcontextprotocol.io/posts/2026-07-28/" rel="noopener noreferrer"&gt;finalized on schedule on July 28, 2026&lt;/a&gt; and is now the current protocol version. It turns every remote MCP server into a formal OAuth 2.1 resource server. No more bring-your-own-token. No more skipping auth because your server only talks to internal agents.&lt;/p&gt;

&lt;p&gt;That's not the only breaking change. Sessions are gone. The &lt;code&gt;initialize&lt;/code&gt; handshake is gone. The Tasks feature moved out of core into an extension. Here's exactly what changed, what you need to fix, and what still has a 12-month grace period.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changed in the MCP 2026-07-28 Spec
&lt;/h2&gt;

&lt;p&gt;The release candidate locked on May 21, 2026, giving SDK maintainers a 10-week validation window, and the final spec published on July 28 as planned. Per &lt;a href="https://blog.modelcontextprotocol.io/posts/2026-07-28/" rel="noopener noreferrer"&gt;the official spec blog&lt;/a&gt;, this is the biggest rewrite since MCP launched — the protocol moves from bidirectional and stateful to request/response and stateless — and it touches four areas at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transport&lt;/strong&gt; — protocol-level sessions and the &lt;code&gt;Mcp-Session-Id&lt;/code&gt; header are gone from Streamable HTTP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle&lt;/strong&gt; — the &lt;code&gt;initialize&lt;/code&gt;/&lt;code&gt;initialized&lt;/code&gt; handshake is gone entirely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks&lt;/strong&gt; — the async task feature graduated from experimental core into an official extension, with a different API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization&lt;/strong&gt; — MCP servers are now OAuth 2.1 resource servers, full stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this was a soft rollout. Servers on the 2026-07-28 revision won't necessarily work with older clients, and the reverse is also true. If you maintain a public or internal MCP server and haven't audited against the final spec yet, you're already a month behind the clients and SDKs that have.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP Server Authentication Becomes Mandatory OAuth 2.1
&lt;/h2&gt;

&lt;p&gt;This is the change with the most real search volume behind it. That makes sense — it touches every server that accepts remote connections. Per &lt;a href="https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization" rel="noopener noreferrer"&gt;the final authorization spec&lt;/a&gt; and &lt;a href="https://workos.com/blog/mcp-2026-spec-agent-authentication" rel="noopener noreferrer"&gt;WorkOS's breakdown&lt;/a&gt;, the spec now requires things your server didn't need before:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protected Resource Metadata (RFC 9728).&lt;/strong&gt; Your server must expose a &lt;code&gt;.well-known/oauth-protected-resource&lt;/code&gt; endpoint. Or it can include &lt;code&gt;resource_metadata&lt;/code&gt; in its &lt;code&gt;WWW-Authenticate&lt;/code&gt; header instead. Either way, clients can discover your authorization server automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;WWW-Authenticate: Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resource Indicators (RFC 8707).&lt;/strong&gt; Clients must now name the specific MCP server a token is meant for when they request it. This closes a real gap. Without a resource indicator, a token issued for one MCP server could get replayed against a different one. With it, the authorization server binds the token to a single audience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issuer verification (RFC 9207).&lt;/strong&gt; Authorization servers should include the &lt;code&gt;iss&lt;/code&gt; parameter, and clients must validate it whenever it's present — the final spec softened this from the release candidate's mandatory framing, and says a future revision is expected to make inclusion a hard requirement. Either way, if you migrate your MCP server to a different auth provider, existing clients need to re-register. There's no silent handoff.&lt;/p&gt;

&lt;p&gt;On top of that, the spec deprecates Dynamic Client Registration (RFC 7591) in favor of Client ID Metadata Documents (CIMD). DCR keeps working for now, but CIMD is the preferred registration path going forward. Clients still registering through DCR must also declare an OpenID Connect &lt;code&gt;application_type&lt;/code&gt; — something the old spec never asked for.&lt;/p&gt;

&lt;p&gt;This lands three months after security researchers at OX Security &lt;a href="https://thehackernews.com/2026/04/anthropic-mcp-design-vulnerability.html" rel="noopener noreferrer"&gt;disclosed a design flaw in the MCP SDK's STDIO transport&lt;/a&gt; that let arbitrary commands execute across more than 7,000 public servers. That RCE was a different transport and a different bug. This spec update doesn't patch it. What it does fix is a gap the STDIO issue never touched: a standard way for a server to confirm a token belongs to it, not to a callback meant for someone else. If you already run runtime security tooling like &lt;a href="https://devtoolhub.com/falco-kubernetes-runtime-security/" rel="noopener noreferrer"&gt;Falco on Kubernetes&lt;/a&gt; to catch anomalous process execution, treat this as the same category of gap, closed at a different layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sessions and the Initialize Handshake Are Gone
&lt;/h2&gt;

&lt;p&gt;If your server tracks state using &lt;code&gt;Mcp-Session-Id&lt;/code&gt;, that header no longer exists on Streamable HTTP. Client info that used to travel through the &lt;code&gt;initialize&lt;/code&gt;/&lt;code&gt;initialized&lt;/code&gt; exchange now rides in &lt;code&gt;_meta&lt;/code&gt; on every request instead. Look for fields like &lt;code&gt;io.modelcontextprotocol/protocolVersion&lt;/code&gt;, &lt;code&gt;/clientInfo&lt;/code&gt;, and &lt;code&gt;/clientCapabilities&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Practically, this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace any session-based state with a server-issued handle passed back as a regular tool argument&lt;/li&gt;
&lt;li&gt;Implement the new &lt;code&gt;server/discover&lt;/code&gt; RPC endpoint for capability negotiation&lt;/li&gt;
&lt;li&gt;Expect an &lt;code&gt;UnsupportedProtocolVersionError&lt;/code&gt; instead of a failed handshake when a client's version doesn't match&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kills sticky-session routing requirements entirely. A stateless MCP server behind a plain load balancer becomes a normal deployment instead of a special case. You no longer need session affinity just to keep a client talking to the same backend instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating the Tasks Extension
&lt;/h2&gt;

&lt;p&gt;If your server uses Tasks for long-running operations, the spec replaces the experimental &lt;code&gt;2025-11-25&lt;/code&gt; API. It removes &lt;code&gt;tasks/list&lt;/code&gt; outright. You now drive the lifecycle with &lt;code&gt;tasks/get&lt;/code&gt;, &lt;code&gt;tasks/update&lt;/code&gt;, and &lt;code&gt;tasks/cancel&lt;/code&gt;. Servers can hand back a task handle without a client opting in first.&lt;/p&gt;

&lt;p&gt;The same revision introduces a core-protocol pattern (separate from the tasks extension) for anything that used to hold a connection open waiting on the client. Instead of a server-initiated callback, a call returns an &lt;code&gt;InputRequiredResult&lt;/code&gt; carrying &lt;code&gt;inputRequests&lt;/code&gt; and an opaque &lt;code&gt;requestState&lt;/code&gt;. The client gathers what it needs and re-issues the original call with &lt;code&gt;inputResponses&lt;/code&gt; and the echoed &lt;code&gt;requestState&lt;/code&gt;. All the state lives in the payload instead of an open connection. That means any server instance can process the retry — the same stateless principle driving the session removal. One addition that landed between the release candidate and the final spec supports this: every result now carries a required &lt;code&gt;resultType&lt;/code&gt; field, &lt;code&gt;"complete"&lt;/code&gt; or &lt;code&gt;"input_required"&lt;/code&gt;, so clients can tell a finished call from one waiting on input without guessing from the payload's shape.&lt;/p&gt;

&lt;p&gt;[IMAGE: articles/images/2026-07-25-mcp-server-authentication-spec-update-diagram.png | alt: "MCP client to authorization server to MCP server auth flow with resource indicators"]&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Deprecated, Not Removed Yet
&lt;/h2&gt;

&lt;p&gt;Three features get a 12-month minimum deprecation window instead of an immediate cut, under the new lifecycle policy (SEP-2596):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Roots&lt;/strong&gt; — replaced by tool parameters, resource URIs, or server-side config&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sampling&lt;/strong&gt; — replaced by direct integration with your LLM provider's API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt; — replaced by &lt;code&gt;stderr&lt;/code&gt; on stdio transports or OpenTelemetry for anything else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't have to touch these immediately. But treat the window as a countdown, not a reprieve. The spec's new governance model requires a conformance suite before any feature reaches "Final" status, and these three didn't make the cut.&lt;/p&gt;

&lt;p&gt;One smaller change worth knowing: the error code for a missing resource changes too. It moves from the MCP-specific &lt;code&gt;-32002&lt;/code&gt; to the standard JSON-RPC &lt;code&gt;-32602&lt;/code&gt; (Invalid Params). If you have client code branching on the old code, that branch stops firing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist: Locking Down MCP Server Authentication Against the Final Spec
&lt;/h2&gt;

&lt;p&gt;For most self-hosted or internal MCP servers, authorization hardening matters more than the transport changes. Work through this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm your server exposes &lt;code&gt;.well-known/oauth-protected-resource&lt;/code&gt; or sets &lt;code&gt;resource_metadata&lt;/code&gt; on &lt;code&gt;WWW-Authenticate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check that your authorization server issues tokens scoped with a resource indicator naming your specific MCP server&lt;/li&gt;
&lt;li&gt;Verify &lt;code&gt;iss&lt;/code&gt; validation is happening on the client side, not just token signature checks&lt;/li&gt;
&lt;li&gt;Audit any code that reads &lt;code&gt;Mcp-Session-Id&lt;/code&gt; or relies on the &lt;code&gt;initialize&lt;/code&gt; handshake — both need replacing before older clients start failing silently&lt;/li&gt;
&lt;li&gt;If you use Tasks, migrate off &lt;code&gt;tasks/list&lt;/code&gt; and the &lt;code&gt;2025-11-25&lt;/code&gt; polling model now, while you can still test against both old and new clients&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're newer to the protocol itself, the site's &lt;a href="https://devtoolhub.com/mcp-model-context-protocol-guide/" rel="noopener noreferrer"&gt;Model Context Protocol guide&lt;/a&gt; covers the architecture this revision rewrites. And if you're building these servers as part of a broader Claude integration, &lt;a href="https://devtoolhub.com/anthropic-academy-free-claude-courses/" rel="noopener noreferrer"&gt;Anthropic's own developer training track&lt;/a&gt; covers MCP alongside Agent Skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Do I have to rewrite my MCP server now that the spec is final?&lt;/strong&gt;&lt;br&gt;
A: If your server only talks to clients you control, you have flexibility to upgrade both sides together. If you run a public or third-party-facing MCP server, prioritize the OAuth 2.1 changes now — SDKs built against the final spec are already shipping, and older clients and new servers won't necessarily interoperate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does the new spec fix the MCP STDIO RCE from April 2026?&lt;/strong&gt;&lt;br&gt;
A: No. That vulnerability was in the STDIO transport's command execution model. Anthropic characterized the underlying behavior as expected, not as a bug to patch. The July 28 update hardens OAuth-based authorization for remote transports — a related but separate concern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What happens if my client still sends Mcp-Session-Id to a 2026-07-28 server?&lt;/strong&gt;&lt;br&gt;
A: A server built against the new spec won't recognize it. Protocol-level sessions no longer exist on Streamable HTTP. You need to move that state into request payloads or &lt;code&gt;_meta&lt;/code&gt; fields instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is Dynamic Client Registration completely removed?&lt;/strong&gt;&lt;br&gt;
A: No — the spec deprecates it in favor of Client ID Metadata Documents, but DCR support continues for backward compatibility. New integrations should register with CIMD.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Did Roots, Sampling, and Logging stop working when the spec finalized?&lt;/strong&gt;&lt;br&gt;
A: No. The spec deprecates them with a minimum 12-month window before removal. Existing implementations keep functioning while you migrate to the replacements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The MCP 2026-07-28 spec, final and current since July 28, makes OAuth 2.1 mandatory for remote servers: Protected Resource Metadata (RFC 9728), Resource Indicators (RFC 8707), and RFC 9207 issuer verification (client-side validation required whenever &lt;code&gt;iss&lt;/code&gt; is present)&lt;/li&gt;
&lt;li&gt;Sessions (&lt;code&gt;Mcp-Session-Id&lt;/code&gt;) and the &lt;code&gt;initialize&lt;/code&gt;/&lt;code&gt;initialized&lt;/code&gt; handshake are removed from Streamable HTTP — client info now travels in &lt;code&gt;_meta&lt;/code&gt; on every request&lt;/li&gt;
&lt;li&gt;Tasks graduates from experimental core to an official extension; &lt;code&gt;tasks/list&lt;/code&gt; is removed in favor of &lt;code&gt;tasks/get&lt;/code&gt; and &lt;code&gt;tasks/update&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Roots, Sampling, and Logging are deprecated with a 12-month minimum window, not removed outright&lt;/li&gt;
&lt;li&gt;Dynamic Client Registration is deprecated in favor of Client ID Metadata Documents, though DCR still works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Audit your MCP server's auth flow against the checklist above this week. The spec has been final for a month, SDKs targeting it are already in the wild, and every week of delay widens the gap between your server and the clients calling it.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>modelcontextprotocol</category>
      <category>oauth</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>Ollama Model Library, By the Numbers</title>
      <dc:creator>Amaresh Pelleti</dc:creator>
      <pubDate>Sun, 06 Sep 2026 14:21:50 +0000</pubDate>
      <link>https://dev.to/amareswer/ollama-model-library-by-the-numbers-43n1</link>
      <guid>https://dev.to/amareswer/ollama-model-library-by-the-numbers-43n1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://devtoolhub.com/ollama-model-library-by-the-numbers/" rel="noopener noreferrer"&gt;DevToolHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Someone asks "what's the best Ollama model" in a Discord or a Reddit thread almost every day. The answer usually comes from memory, or a single favorite. So &lt;a href="https://ollama.com/library" rel="noopener noreferrer"&gt;we pulled the actual data&lt;/a&gt; instead. Every model in the Ollama model library, its pull count, its capability tags, and when it was last updated. Current as of September 5, 2026 — the library changes weekly, so treat these counts as a snapshot, not a permanent ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the Ollama model library right now
&lt;/h2&gt;

&lt;p&gt;The Ollama model library holds 239 models as of this pull. That spans general chat models, embeddings, vision models, and a growing "cloud" category that runs on Ollama's hosted infrastructure instead of your GPU. Combined, every model in the library has been pulled just over 1.04 billion times.&lt;/p&gt;

&lt;p&gt;That total tells you less than it looks like it should. Pulls aren't spread evenly. A handful of general-purpose chat models account for most of it. The long tail of specialized or older models barely registers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Ollama model library pulls actually concentrate
&lt;/h2&gt;

&lt;p&gt;The top 10 models by pull count account for 56.4% of all pulls in the entire library. Meta's Llama family and DeepSeek's reasoning models lead by a wide margin:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Pulls&lt;/th&gt;
&lt;th&gt;Capabilities&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;llama3.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;119.2M&lt;/td&gt;
&lt;td&gt;tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deepseek-r1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;92.4M&lt;/td&gt;
&lt;td&gt;tools, thinking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nomic-embed-text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;84.6M&lt;/td&gt;
&lt;td&gt;embedding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;llama3.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;82.4M&lt;/td&gt;
&lt;td&gt;tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemma3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;40.1M&lt;/td&gt;
&lt;td&gt;vision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;qwen2.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;39.3M&lt;/td&gt;
&lt;td&gt;tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;qwen3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;36.3M&lt;/td&gt;
&lt;td&gt;tools, thinking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mistral&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;33.3M&lt;/td&gt;
&lt;td&gt;tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gemma2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;31.8M&lt;/td&gt;
&lt;td&gt;text only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;llama3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;25.2M&lt;/td&gt;
&lt;td&gt;text only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's the thing about that list: it's mostly older releases. &lt;code&gt;llama3.1&lt;/code&gt; and &lt;code&gt;llama3.2&lt;/code&gt; alone outpull every newer Llama version combined. &lt;code&gt;llama3&lt;/code&gt; — several generations behind — still sits at 25.2M pulls. That's because pull counts accumulate over a model's lifetime. An older model with a long track record will always look bigger than a newer one that's objectively better. Don't read this table as "what to use today." Read it as "what people have been defaulting to."&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nomic-embed-text&lt;/code&gt; at #3 breaks the chat-model pattern. It's a pure embedding model. Its position this high says a lot about how much RAG and semantic-search tooling runs on Ollama underneath the chat interfaces people actually see.&lt;/p&gt;

&lt;h2&gt;
  
  
  How many Ollama models actually support tool calling
&lt;/h2&gt;

&lt;p&gt;If you're building an agent, this number matters more than pull count. Only 93 of 239 models (38.9%) carry the &lt;code&gt;tools&lt;/code&gt; capability tag. The rest either don't support structured tool calling, or Ollama hasn't tagged them for it.&lt;/p&gt;

&lt;p&gt;The full capability breakdown across the library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools (function calling):&lt;/strong&gt; 93 models — 38.9%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thinking (extended reasoning):&lt;/strong&gt; 42 models — 17.6%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vision:&lt;/strong&gt; 38 models — 15.9%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud (hosted, not local):&lt;/strong&gt; 18 models — 7.5%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding:&lt;/strong&gt; 12 models — 5.0%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No special tag (plain text completion):&lt;/strong&gt; 118 models — 49.4%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These overlap — a model like &lt;code&gt;gemma4&lt;/code&gt; carries vision, tools, thinking, and cloud tags at once. But the practical read is simple. Half the library is plain text completion. If your use case needs tool calling specifically, you're choosing from under 40% of what's listed. Check a model's tags on its &lt;a href="https://ollama.com/library" rel="noopener noreferrer"&gt;library page&lt;/a&gt; before you build around it, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Ollama model library carries 7,359 tag variants
&lt;/h2&gt;

&lt;p&gt;Across all 239 models, there are 7,359 individual tags. Each one is a different quantization, parameter size, or context configuration of the same base model. That averages out to roughly 30.8 variants per model, though it's lopsided — &lt;code&gt;llama3.1&lt;/code&gt; alone carries 93 tags, while a narrow embedding model might have 3.&lt;/p&gt;

&lt;p&gt;This ties into the same issue covered in the &lt;a href="https://devtoolhub.com/ollama-vs-lm-studio/" rel="noopener noreferrer"&gt;Ollama vs LM Studio comparison&lt;/a&gt;. Ollama's model names default to a specific quantization, usually &lt;code&gt;Q4_K_M&lt;/code&gt;, a 4-bit quant, without making that choice obvious on the model card. With 30+ tagged variants per model on average, "the model" isn't one thing — it's a family. The tag you don't specify is a decision Ollama makes for you. If you're benchmarking against another tool, pin the exact tag (&lt;code&gt;ollama pull llama3.1:8b-instruct-q8_0&lt;/code&gt;, for example) instead of the bare model name.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much of the Ollama model library is still maintained
&lt;/h2&gt;

&lt;p&gt;Freshness in the library skews old. Of the 239 models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;174 (72.8%)&lt;/strong&gt; were last updated over a year ago&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;51 (21.3%)&lt;/strong&gt; were updated sometime this year&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9 (3.8%)&lt;/strong&gt; were updated this month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 (2.1%)&lt;/strong&gt; were updated this week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nearly three-quarters of the library hasn't been touched in over a year. That's not automatically a red flag. A model's weights don't need updates the way a CLI tool does, and a good 2024 model is often still a good model. But it does mean the library is mostly an archive with a small, actively-tended front section. If a model card shows no update in over a year, and a same-family successor has recent activity, the successor is usually the safer default.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means if you're picking a model to run
&lt;/h2&gt;

&lt;p&gt;Two practical takeaways come out of this data. First, pull count is a popularity signal, not a quality signal. It rewards models that have been available the longest. That's why year-old Llama releases still outrank newer, often better models. Cross-check pull count against a model's actual release date before treating it as a recommendation.&lt;/p&gt;

&lt;p&gt;Second, the capability tags are the fastest filter for narrowing 239 models down to the ones that fit your use case. Building an agent? Filter to the 93 &lt;code&gt;tools&lt;/code&gt;-tagged models first. Need a local embedding model for RAG? &lt;code&gt;nomic-embed-text&lt;/code&gt; and &lt;code&gt;mxbai-embed-large&lt;/code&gt; are the two with real usage behind them. For everything else — running the model once you've picked it — the &lt;a href="https://devtoolhub.com/ollama-hardware-requirements/" rel="noopener noreferrer"&gt;hardware requirements guide&lt;/a&gt; and the &lt;a href="https://devtoolhub.com/ollama-api-guide/" rel="noopener noreferrer"&gt;Ollama API guide&lt;/a&gt; cover the setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: How many models are in the Ollama library?&lt;/strong&gt;&lt;br&gt;
A: 239 models as of September 5, 2026. The Ollama model library is updated regularly, so this number changes — check &lt;a href="https://ollama.com/library" rel="noopener noreferrer"&gt;ollama.com/library&lt;/a&gt; directly for the current count.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What is the most popular model in the Ollama library?&lt;/strong&gt;&lt;br&gt;
A: &lt;code&gt;llama3.1&lt;/code&gt;, with 119.2 million pulls, ahead of &lt;code&gt;deepseek-r1&lt;/code&gt; at 92.4 million and &lt;code&gt;nomic-embed-text&lt;/code&gt; at 84.6 million. All three are well over a year old, which is typical — pull counts accumulate over time and favor established models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How many Ollama models support function calling?&lt;/strong&gt;&lt;br&gt;
A: 93 of 239 models (38.9%) carry the &lt;code&gt;tools&lt;/code&gt; capability tag, which indicates support for structured function calling. Check the individual model's page on ollama.com to confirm before building an agent around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Why does Ollama have so many tags for one model?&lt;/strong&gt;&lt;br&gt;
A: Each tag is a different quantization, parameter size, or configuration of the same base model. The library averages about 30.8 tags per model, and the untagged default usually points to a 4-bit quantization rather than the highest-quality version available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Summary:&lt;/strong&gt;&lt;br&gt;
– 239 models in the Ollama model library as of September 5, 2026, with 1.04 billion cumulative pulls.&lt;br&gt;
– The top 10 models account for 56.4% of all pulls — usage concentrates hard in a handful of established releases.&lt;br&gt;
– Only 38.9% of models carry the &lt;code&gt;tools&lt;/code&gt; (function-calling) tag; 49.4% have no special capability tag at all.&lt;br&gt;
– The library averages 30.8 tag variants per model, so the untagged default is a quantization choice you're making without realizing it.&lt;br&gt;
– 72.8% of models haven't been updated in over a year — the library is mostly an archive with a small active front section.&lt;/p&gt;

&lt;p&gt;If you've picked a model from this list and need to know whether your hardware can run it, the &lt;a href="https://devtoolhub.com/ollama-hardware-requirements/" rel="noopener noreferrer"&gt;Ollama hardware requirements guide&lt;/a&gt; breaks down RAM and VRAM by model size. And if local hardware runs out before your model does, the &lt;a href="https://devtoolhub.com/ollama-cloud-free-vs-pro-limits-pricing-2026/" rel="noopener noreferrer"&gt;Ollama Cloud pricing and limits guide&lt;/a&gt; covers the hosted tier.&lt;/p&gt;

</description>
      <category>ollama</category>
      <category>localllm</category>
      <category>aitools</category>
      <category>opensourcemodels</category>
    </item>
  </channel>
</rss>
