<?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: Amir Pournasserian</title>
    <description>The latest articles on DEV Community by Amir Pournasserian (@pournasserian).</description>
    <link>https://dev.to/pournasserian</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%2F1487471%2F7a03a69c-2bd6-40f8-b316-4a54e469af06.png</url>
      <title>DEV Community: Amir Pournasserian</title>
      <link>https://dev.to/pournasserian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pournasserian"/>
    <language>en</language>
    <item>
      <title>How to evaluate an AI router's 'none of these' branch</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Fri, 06 Nov 2026 21:56:18 +0000</pubDate>
      <link>https://dev.to/pournasserian/how-to-evaluate-an-ai-routers-none-of-these-branch-3jhh</link>
      <guid>https://dev.to/pournasserian/how-to-evaluate-an-ai-routers-none-of-these-branch-3jhh</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu5k2ph15lhvawikh9pae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu5k2ph15lhvawikh9pae.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An AI router has to recognize requests outside its supported categories while still accepting useful work. Those are two different things to measure.&lt;/p&gt;

&lt;p&gt;Between 23 and 28 October 2026, I compared four decision models and five small language models. This article focuses on one task from that comparison: choosing a domain for a request, including an explicit "out of scope" option.&lt;/p&gt;

&lt;p&gt;The decision models received typed questions and returned probabilities over the options. The language models received the same questions and guidance as text, with their answers constrained to a JSON schema. No models were fine-tuned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the router somewhere to decline
&lt;/h2&gt;

&lt;p&gt;I used 1,000 sampled requests from the CLINC150 test split, mapped to ten domains, with an eleventh option for requests outside those domains.&lt;/p&gt;

&lt;p&gt;Of those requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;190 were genuinely out of scope.&lt;/li&gt;
&lt;li&gt;810 belonged to a supported domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every model received the same guidance for the out-of-scope option. The resulting behavior varied substantially.&lt;/p&gt;

&lt;p&gt;Here are three examples from the nine-model comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Out-of-scope requests correctly declined, of 190&lt;/th&gt;
&lt;th&gt;Out-of-scope requests missed, of 190&lt;/th&gt;
&lt;th&gt;In-scope requests wrongly declined, of 810&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mammoth-1&lt;/td&gt;
&lt;td&gt;152&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kev-4B&lt;/td&gt;
&lt;td&gt;136&lt;/td&gt;
&lt;td&gt;54&lt;/td&gt;
&lt;td&gt;239&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 nano&lt;/td&gt;
&lt;td&gt;46&lt;/td&gt;
&lt;td&gt;144&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The false-alarm counts come from subtracting correct rejections from total out-of-scope answers. Mammoth-1 selected that option 252 times: 152 correct rejections and 100 false alarms.&lt;/p&gt;

&lt;p&gt;Kev-4B selected it 375 times, yet caught fewer genuinely out-of-scope requests. GPT-5.4 nano rejected only 18 valid requests, but missed 144 requests it should have declined.&lt;/p&gt;

&lt;p&gt;A rejection count alone hides both kinds of error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Score the branch separately
&lt;/h2&gt;

&lt;p&gt;For a router with an out-of-scope option, I would report three measures alongside overall accuracy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Out-of-scope recall:&lt;/strong&gt; correctly declined out-of-scope requests divided by all truly out-of-scope requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;False-rejection rate:&lt;/strong&gt; in-scope requests wrongly declined divided by all truly in-scope requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-scope routing accuracy:&lt;/strong&gt; requests assigned to their correct domain divided by all truly in-scope requests, including those wrongly declined.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this sample, the first denominator is 190 and the other two are 810.&lt;/p&gt;

&lt;p&gt;For Mammoth-1, out-of-scope recall is 152/190, or 80%. Its false-rejection rate is 100/810. Its reported in-scope routing accuracy is 83.7%.&lt;/p&gt;

&lt;p&gt;Keeping domain accuracy separate matters. A router can accept a valid request and still send it to the wrong destination.&lt;/p&gt;

&lt;p&gt;I would also track malformed answers and request failures separately. In my benchmark, format failures counted as wrong in overall accuracy; they were not dropped to make the successful responses look better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply the test to your own router
&lt;/h2&gt;

&lt;p&gt;I would start by writing down exactly which requests each destination supports. Then I would build a labeled evaluation set containing both supported requests and plausible requests outside that scope.&lt;/p&gt;

&lt;p&gt;For an initial comparison, keep the requests, category definitions and option guidance consistent across models. Record the model versions and settings so that a later run has a useful reference point.&lt;/p&gt;

&lt;p&gt;After scoring, inspect examples from each error category. A false rejection may point to narrow option guidance. A missed out-of-scope request may expose an unclear boundary between supported and unsupported work. These are possibilities to investigate in the examples.&lt;/p&gt;

&lt;p&gt;The choice depends on what those mistakes cost in the application. Sending unsupported work into a workflow and declining a valid customer request can have very different consequences.&lt;/p&gt;

&lt;p&gt;If I added a confidence threshold, I would evaluate it on separate validation data and check calibration. The counts above describe the options the models selected; they do not establish an optimal threshold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect the experiment
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/pournasserian/decision-models-vs-small-llms" rel="noopener noreferrer"&gt;public repository&lt;/a&gt; contains the harness, task definitions, raw requests and responses, and reports.&lt;/p&gt;

&lt;p&gt;Start with the &lt;a href="https://github.com/pournasserian/decision-models-vs-small-llms/tree/master/results" rel="noopener noreferrer"&gt;saved results&lt;/a&gt; and &lt;a href="https://github.com/pournasserian/decision-models-vs-small-llms/tree/master/reports" rel="noopener noreferrer"&gt;reports&lt;/a&gt; to examine the existing experiment. The repository's README explains how to run it again.&lt;/p&gt;

&lt;p&gt;These results describe the tested model versions on public data in October 2026. Model-specific prompting or fine-tuning could change the outcome. All nine models ran this CLINC task, and a production router still needs evaluation on its own traffic.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pournasserian.com/writing/decision-models-vs-small-llms-2026" rel="noopener noreferrer"&gt;full comparison on my site&lt;/a&gt; also covers calibration, format failures, latency, cost and repeatability across the other tasks.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Decision models against small LLMs: Jev, Kev, Laya and Mammoth-1 on 6,662 decisions</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Thu, 05 Nov 2026 23:24:59 +0000</pubDate>
      <link>https://dev.to/pournasserian/decision-models-against-small-llms-jev-kev-laya-and-mammoth-1-on-6662-decisions-1i7k</link>
      <guid>https://dev.to/pournasserian/decision-models-against-small-llms-jev-kev-laya-and-mammoth-1-on-6662-decisions-1i7k</guid>
      <description>&lt;p&gt;Four decision models and five small LLMs on 6,662 decisions: accuracy, calibration, format failures, latency and cost, every call published.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://pournasserian.com/writing/decision-models-vs-small-llms-2026" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpournasserian.com%2Fshare%2Fdecision-models-vs-small-llms-2026-d7d95378cae4.jpg" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://pournasserian.com/writing/decision-models-vs-small-llms-2026" rel="noopener noreferrer" class="c-link"&gt;
            Decision models against small LLMs, measured | Amir Pournasserian
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Four decision models and five small LLMs on the same 6,662 decisions: accuracy, calibration, format failures, latency and cost, every call published.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpournasserian.com%2Ffavicon.svg" width="64" height="64"&gt;
          pournasserian.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>llm</category>
      <category>ai</category>
      <category>jev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Validating a vector database built for RAG: four layers of checks, with the code to run them</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Thu, 05 Nov 2026 23:23:01 +0000</pubDate>
      <link>https://dev.to/pournasserian/validating-a-vector-database-built-for-rag-four-layers-of-checks-with-the-code-to-run-them-2lmg</link>
      <guid>https://dev.to/pournasserian/validating-a-vector-database-built-for-rag-four-layers-of-checks-with-the-code-to-run-them-2lmg</guid>
      <description>&lt;p&gt;How to check a RAG vector index on its own, in four layers from the chunks to the answer, with runnable Python and 25 evaluation tools compared.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://pournasserian.com/writing/validating-a-vector-database-for-rag" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpournasserian.com%2Fshare%2Fvalidating-a-vector-database-for-rag-dc86d5ef7ee9.jpg" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://pournasserian.com/writing/validating-a-vector-database-for-rag" rel="noopener noreferrer" class="c-link"&gt;
            Validating a vector database built for RAG: four layers of checks
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            How to check a RAG vector index on its own, in four layers from the chunks to the answer, with runnable Python and 25 evaluation tools compared.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpournasserian.com%2Ffavicon.svg" width="64" height="64"&gt;
          pournasserian.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>vectordatabase</category>
    </item>
    <item>
      <title>I tested four decision models against five small LLMs on 6,662 decisions. The strongest model changed by task, and the full harness and raw calls are public.

https://pournasserian.com/writing/decision-models-vs-small-llms-2026</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Thu, 05 Nov 2026 23:20:31 +0000</pubDate>
      <link>https://dev.to/pournasserian/i-tested-four-decision-models-against-five-small-llms-on-6662-decisions-the-strongest-model-314h</link>
      <guid>https://dev.to/pournasserian/i-tested-four-decision-models-against-five-small-llms-on-6662-decisions-the-strongest-model-314h</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://pournasserian.com/writing/decision-models-vs-small-llms-2026" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpournasserian.com%2Fshare%2Fdecision-models-vs-small-llms-2026-d7d95378cae4.jpg" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://pournasserian.com/writing/decision-models-vs-small-llms-2026" rel="noopener noreferrer" class="c-link"&gt;
            Decision models against small LLMs, measured | Amir Pournasserian
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Four decision models and five small LLMs on the same 6,662 decisions: accuracy, calibration, format failures, latency and cost, every call published.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpournasserian.com%2Ffavicon.svg" width="64" height="64"&gt;
          pournasserian.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Buying an MCP server? Ask these 12 questions first</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Sat, 24 Oct 2026 12:49:20 +0000</pubDate>
      <link>https://dev.to/pournasserian/buying-an-mcp-server-ask-these-12-questions-first-c1c</link>
      <guid>https://dev.to/pournasserian/buying-an-mcp-server-ask-these-12-questions-first-c1c</guid>
      <description>&lt;p&gt;A vendor demo can make an MCP server look great.&lt;/p&gt;

&lt;p&gt;The tools work, the assistant gets useful answers, and everything feels effortless.&lt;/p&gt;

&lt;p&gt;But what happens when a token expires, a user cancels a long-running request, or your company needs evidence that the server is actually secure?&lt;/p&gt;

&lt;p&gt;That's the part worth investigating before signing a contract. 🙂&lt;/p&gt;

&lt;p&gt;I published a practical guide to evaluating MCP server vendors, based on the 2026-07-28 Model Context Protocol specification.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the checklist?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Protocol compliance
&lt;/h3&gt;

&lt;p&gt;Does the server implement discovery correctly? Can any instance handle a request without relying on connection-specific session state? Are caching and transport requirements respected?&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Security
&lt;/h3&gt;

&lt;p&gt;How are tokens validated? Does the server check the intended audience? Are inputs validated, tool calls rate-limited, and outputs sanitized?&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Production operations
&lt;/h3&gt;

&lt;p&gt;What happens when a client disconnects or cancels a request? Can the vendor show useful metrics, tracing, and operational logs?&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Evidence, not promises
&lt;/h3&gt;

&lt;p&gt;Does the vendor run the official conformance suite? Does it test against both older and newer protocol implementations? Has it been tested across multiple AI hosts, including a text-only client?&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful part: 12 questions you can actually send
&lt;/h2&gt;

&lt;p&gt;The article ends with a one-page checklist designed for buyers, CTOs, security reviewers, and engineering teams.&lt;/p&gt;

&lt;p&gt;It distinguishes requirements stated by the specification from my own recommendations, so you're not accidentally turning a good practice into a supposed protocol MUST.&lt;/p&gt;

&lt;p&gt;The goal isn't to make procurement harder. It's to make the important questions easier to ask before a production incident asks them for you. 😅&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Read the full article:&lt;/strong&gt; &lt;a href="https://pournasserian.com/writing/mcp-buyer-vendor-requirements" rel="noopener noreferrer"&gt;https://pournasserian.com/writing/mcp-buyer-vendor-requirements&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is part one of a series on MCP for buyers and CTOs. I'd love to hear what you'd add to the checklist, especially if you've already evaluated MCP vendors for production use.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>development</category>
      <category>webdev</category>
    </item>
    <item>
      <title>MCP subscriptions/listen: change notifications without the surprises</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Fri, 23 Oct 2026 16:05:26 +0000</pubDate>
      <link>https://dev.to/pournasserian/mcp-subscriptionslisten-change-notifications-without-the-surprises-355d</link>
      <guid>https://dev.to/pournasserian/mcp-subscriptionslisten-change-notifications-without-the-surprises-355d</guid>
      <description>&lt;p&gt;Opening a stream is easy. Keeping it useful when connections drop and your server runs across multiple instances? That's where things get interesting. 😅&lt;/p&gt;

&lt;p&gt;I just published a practical walkthrough of subscriptions/listen in the 2026 Model Context Protocol (MCP) specification.&lt;/p&gt;

&lt;p&gt;What you'll learn&lt;/p&gt;

&lt;p&gt;How subscriptions work: Open a long-lived stream and request the notification types you care about.&lt;/p&gt;

&lt;p&gt;Why acknowledgements matter: The server acknowledges the subscription before sending notifications.&lt;/p&gt;

&lt;p&gt;What notifications actually tell you: They're signals that something changed, not the updated resource itself.&lt;/p&gt;

&lt;p&gt;How reconnects work: Missed events aren't replayed, so clients need to subscribe again and refresh their state.&lt;/p&gt;

&lt;p&gt;What changes when you scale out: Multiple server instances need a shared pub/sub mechanism to keep their subscribers informed.&lt;/p&gt;

&lt;p&gt;A little Python, too&lt;/p&gt;

&lt;p&gt;The article includes examples using the MCP Python SDK (mcp 2.3.0), including how to notify clients when a resource changes and how to think about implementing a subscription bus across multiple server instances.&lt;/p&gt;

&lt;p&gt;I also cover practical details like stream shutdowns, idle timeouts, authentication expiry, and the difference between a clean close and an unexpected disconnect.&lt;/p&gt;

&lt;p&gt;The big takeaway&lt;/p&gt;

&lt;p&gt;Don't treat a subscription as a durable event log.&lt;/p&gt;

&lt;p&gt;If a connection drops, assume you may have missed changes. Reconnect, subscribe again, and refresh whatever state you cached.&lt;/p&gt;

&lt;p&gt;And if you're running multiple instances, remember that a notification generated on one instance won't automatically reach a stream connected to another.&lt;/p&gt;

&lt;p&gt;Distributed systems: finding new ways to remind us that "it works on my machine" is not an architecture. 🙂&lt;/p&gt;

&lt;p&gt;👉 Read the full article: &lt;a href="https://pournasserian.com/writing/mcp-2026-subscriptions-listen" rel="noopener noreferrer"&gt;https://pournasserian.com/writing/mcp-2026-subscriptions-listen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're building MCP servers, I'd love to hear how you're handling subscription fan-out and reconnect recovery in your own setups.&lt;/p&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>mcp</category>
      <category>streaming</category>
    </item>
    <item>
      <title>MCP Elicitation: How AI Agents Ask for Human Input 🤖</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Wed, 21 Oct 2026 15:30:18 +0000</pubDate>
      <link>https://dev.to/pournasserian/mcp-elicitation-how-ai-agents-ask-for-human-input-9ap</link>
      <guid>https://dev.to/pournasserian/mcp-elicitation-how-ai-agents-ask-for-human-input-9ap</guid>
      <description>&lt;p&gt;Sometimes an AI agent can't finish a task without asking a person something.&lt;/p&gt;

&lt;p&gt;Maybe it needs a deployment target. Maybe the user needs to sign in to another service.&lt;/p&gt;

&lt;p&gt;MCP elicitation provides two ways to handle this:&lt;/p&gt;

&lt;p&gt;📝 Form mode: collect structured input, such as choices or missing values.&lt;/p&gt;

&lt;p&gt;🔗 URL mode: send the user to a browser for sign-in, consent, or other sensitive flows.&lt;/p&gt;

&lt;p&gt;In my latest article, I explore how elicitation works under the 2026-07-28 MCP specification, including stateless retries, requestState, capability checks, and a working Python example using mcp 2.3.0.&lt;/p&gt;

&lt;p&gt;One takeaway: design for the case where nobody is there to answer. Not every workflow can avoid human input, but unattended agents need a sensible fallback whenever possible.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://pournasserian.com/writing/mcp-2026-elicitation" rel="noopener noreferrer"&gt;Read the full article&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How are you handling human-in-the-loop steps in your MCP servers?&lt;/p&gt;

&lt;h1&gt;
  
  
  MCP #AI #Python #AIAgents
&lt;/h1&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>mcp</category>
      <category>python</category>
    </item>
    <item>
      <title>51 Open-Source AI Chat Apps Compared: Which One Fits Your Workflow?</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Mon, 19 Oct 2026 16:12:04 +0000</pubDate>
      <link>https://dev.to/pournasserian/51-open-source-ai-chat-apps-compared-which-one-fits-your-workflow-55k1</link>
      <guid>https://dev.to/pournasserian/51-open-source-ai-chat-apps-compared-which-one-fits-your-workflow-55k1</guid>
      <description>&lt;p&gt;Looking for a ChatGPT-style experience without being locked into one provider? The open-source ecosystem has plenty of options — maybe too many. 😅&lt;/p&gt;

&lt;p&gt;I mapped 51 apps and compared 12 across 64 selection criteria, including:&lt;br&gt;
🧠 Coding, research, and document chat&lt;br&gt;
🔒 Privacy, telemetry, and offline use&lt;br&gt;
🖥️ Desktop, mobile, and self-hosted deployment&lt;br&gt;
🛠️ MCP support and AI agents&lt;br&gt;
👥 Team features and administration&lt;br&gt;
📜 Licensing and project activity&lt;/p&gt;

&lt;p&gt;The results highlight some useful distinctions. Open WebUI is a strong all-rounder for self-hosted use, DeepChat stands out among installable desktop apps, and Jan and PocketPal AI are worth a look for private, offline workflows.&lt;/p&gt;

&lt;p&gt;But stars aren't quality scores, and feature counts aren't universal verdicts. The article explains the methodology and its limitations, with downloadable spreadsheets so you can apply your own priorities.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://pournasserian.com/writing/open-source-ai-chat-apps-2026" rel="noopener noreferrer"&gt;Read the full comparison&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  AI #OpenSource #SelfHosting #WebDev
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Is Your Website Ready for AI Agents? Here's a Checklist 🤖</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:27:49 +0000</pubDate>
      <link>https://dev.to/pournasserian/is-your-website-ready-for-ai-agents-heres-a-checklist-3n9n</link>
      <guid>https://dev.to/pournasserian/is-your-website-ready-for-ai-agents-heres-a-checklist-3n9n</guid>
      <description>&lt;p&gt;Making a website AI-friendly is more than adding an &lt;code&gt;llms.txt&lt;/code&gt; file and hoping for the best.&lt;/p&gt;

&lt;p&gt;I put together 8 practical steps, each with a test you can run yourself, covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serving content directly in HTML&lt;/li&gt;
&lt;li&gt;Configuring &lt;code&gt;robots.txt&lt;/code&gt; intentionally&lt;/li&gt;
&lt;li&gt;Keeping sitemaps and feeds fresh&lt;/li&gt;
&lt;li&gt;Publishing Markdown versions of pages&lt;/li&gt;
&lt;li&gt;Supporting coding agents with &lt;code&gt;llms.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Making your site discoverable through MCP&lt;/li&gt;
&lt;li&gt;Measuring verified AI crawler traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The checklist is based on real crawler logs from my site, along with current standards and documentation.&lt;/p&gt;

&lt;p&gt;The goal: less guessing, more evidence.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://pournasserian.com/writing/llm-friendly-website-checklist" rel="noopener noreferrer"&gt;Read the full checklist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; What have you found actually helps AI crawlers discover and understand your website?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I made my website answer ChatGPT and Claude, in .NET</title>
      <dc:creator>Amir Pournasserian</dc:creator>
      <pubDate>Sat, 17 Oct 2026 12:59:52 +0000</pubDate>
      <link>https://dev.to/pournasserian/i-made-my-website-answer-chatgpt-and-claude-in-net-3n79</link>
      <guid>https://dev.to/pournasserian/i-made-my-website-answer-chatgpt-and-claude-in-net-3n79</guid>
      <description>&lt;p&gt;People now ask an assistant before they open a search box. When someone asks ChatGPT or Claude about something I wrote, the answer comes from whatever the model remembers, or from a web search that may or may not land on my pages. I wanted the assistant to be able to ask my site directly and quote the page it used.&lt;/p&gt;

&lt;p&gt;The Model Context Protocol (MCP) is the standard way to do that. A site exposes a server with a few tools, and any MCP client can call them. So I built mcp-my-site: a command-line indexer that crawls a website, and a small ASP.NET Core app that serves the result as a remote MCP server. It is MIT licensed and aimed at small sites, under 1,000 pages.&lt;/p&gt;

&lt;p&gt;You can try it before reading further. A live instance indexes my own site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http pournasserian https://ai.pournasserian.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also a &lt;a href="https://ai.pournasserian.com/playground" rel="noopener noreferrer"&gt;playground&lt;/a&gt;, which is an MCP client in the browser, so you can call the tools without installing anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 60-second version
&lt;/h2&gt;

&lt;p&gt;You need the .NET 10 SDK and, for this first run, nothing else. No API key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; mcpmysite
mcpmysite init https://example.com &lt;span class="nt"&gt;--keyword-only&lt;/span&gt;   &lt;span class="c"&gt;# writes appsettings.json&lt;/span&gt;
mcpmysite build                                     &lt;span class="c"&gt;# crawls the site into ./index&lt;/span&gt;
mcpmysite search &lt;span class="s2"&gt;"how can I contact you"&lt;/span&gt;            &lt;span class="c"&gt;# checks the index&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 5000:8080 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;/index:/index:ro"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;Index__Path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/index ghcr.io/pournasserian/mcp-my-site:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server is then at &lt;code&gt;http://localhost:5000&lt;/code&gt;. &lt;code&gt;/mcp&lt;/code&gt; is the endpoint for agents, &lt;code&gt;/playground&lt;/code&gt; lets you try it in a browser, &lt;code&gt;/api/search?q=contact&lt;/code&gt; returns JSON, and &lt;code&gt;/healthz&lt;/code&gt; shows the loaded index. Connect Claude Code with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http mysite http://localhost:5000/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without Docker you can run the server from a clone of the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design choices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hybrid search, with a fallback.&lt;/strong&gt; Keyword search matches words. Vector search matches meaning, so a question phrased differently from the page still finds it. The server runs BM25 and vector search over embeddings and fuses the two rankings per query. If the embedding provider is unavailable at query time, it falls back to keyword search and says so in the response. The live demo runs hybrid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It works without a key.&lt;/strong&gt; I did not want the first run to start with signing up for something. &lt;code&gt;--keyword-only&lt;/code&gt; builds an index with no vectors, contacts no embeddings endpoint and reads no key. You give up matching by meaning: "how do I reach you" will not find a page that only says "contact". When you want that, change one setting, set &lt;code&gt;AI_API_KEY&lt;/code&gt;, and rebuild. The embeddings endpoint can be OpenRouter, which is the default, or any OpenAI-compatible one: OpenAI, Azure OpenAI, Gemini, Ollama, a LiteLLM proxy. The key is read from the environment and never written to a file. With the default model, a small site embeds for a fraction of a cent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shaped for the ChatGPT connector contract.&lt;/strong&gt; The server speaks MCP over Streamable HTTP and exposes two tools, &lt;code&gt;search&lt;/code&gt; and &lt;code&gt;fetch&lt;/code&gt;. They follow the shape ChatGPT connectors expect: every search result has an &lt;code&gt;id&lt;/code&gt;, and &lt;code&gt;fetch&lt;/code&gt; takes that &lt;code&gt;id&lt;/code&gt; and returns the page as text. Other clients can pass a &lt;code&gt;url&lt;/code&gt; to &lt;code&gt;fetch&lt;/code&gt; instead. The server also sends instructions generated from the site itself, so the model knows what the site is about and when to use the tools. It works with Claude Code, Claude Desktop, VS Code, Cursor and the MCP Inspector.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One site per server.&lt;/strong&gt; There is no multi-tenancy and no admin UI. Configuration is a file, &lt;code&gt;appsettings.json&lt;/code&gt;. The indexer extracts the main content of each page automatically, so there are no CSS selectors to maintain. The server polls the index source and swaps in a new build without a restart, so updating means building in CI and publishing the index folder to a URL the server polls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A search API for your own site.&lt;/strong&gt; The same search code backs &lt;code&gt;GET /api/search&lt;/code&gt;, with CORS, rate limiting and an OpenAPI document. The user guide has a drop-in snippet for a search box.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;It indexes plain HTML pages reachable over HTTP, or a folder of built HTML. JavaScript-rendered sites, PDFs and pages behind a login are out of scope. A build is always a full rebuild, though unchanged chunks are not re-embedded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repository: &lt;a href="https://github.com/pournasserian/mcp-my-site" rel="noopener noreferrer"&gt;https://github.com/pournasserian/mcp-my-site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live demo: &lt;a href="https://ai.pournasserian.com" rel="noopener noreferrer"&gt;https://ai.pournasserian.com&lt;/a&gt; (playground at &lt;code&gt;/playground&lt;/code&gt;, API reference at &lt;code&gt;/docs&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;NuGet: &lt;a href="https://www.nuget.org/packages/mcpmysite" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/mcpmysite&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docker image: &lt;code&gt;ghcr.io/pournasserian/mcp-my-site&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feedback I would like
&lt;/h2&gt;

&lt;p&gt;Three things would help most. First, whether the quick start worked for you as written, and where it did not. Second, how it behaves on your site: pages that were extracted badly, or questions that returned the wrong page. The indexer writes a &lt;code&gt;report.json&lt;/code&gt; that lists low-text pages, and attaching that to an issue helps. Third, which MCP clients you tried it with, especially ChatGPT connectors and anything I have not listed.&lt;/p&gt;

&lt;p&gt;Questions and ideas go to &lt;a href="https://github.com/pournasserian/mcp-my-site/discussions" rel="noopener noreferrer"&gt;Discussions&lt;/a&gt;, bugs to &lt;a href="https://github.com/pournasserian/mcp-my-site/issues" rel="noopener noreferrer"&gt;Issues&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dotnet</category>
      <category>opensource</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
