<?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: Edison Flores</title>
    <description>The latest articles on DEV Community by Edison Flores (@edison_flores_6d2cd381b13).</description>
    <link>https://dev.to/edison_flores_6d2cd381b13</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%2F4011586%2F59d27a5e-b708-4d17-b346-37dce502454e.png</url>
      <title>DEV Community: Edison Flores</title>
      <link>https://dev.to/edison_flores_6d2cd381b13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edison_flores_6d2cd381b13"/>
    <language>en</language>
    <item>
      <title>Verificado en marzo no es evidencia sobre abril: 4 lecciones de diseño para bundles de confianza entre agentes</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Mon, 21 Sep 2026 00:18:34 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/verificado-en-marzo-no-es-evidencia-sobre-abril-4-lecciones-de-diseno-para-bundles-de-confianza-4plb</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/verificado-en-marzo-no-es-evidencia-sobre-abril-4-lecciones-de-diseno-para-bundles-de-confianza-4plb</guid>
      <description>&lt;p&gt;Una propuesta de integración reciente en LlamaIndex — exportar e importar paquetes de memoria sellados (sealed memory bundles) — toca exactamente el problema que operamos a diario: llevar estado verificado entre agentes. Mantenemos un protocolo de tarjetas de confianza (trust cards) para verificación agente-a-agente, donde los bundles sellados y portables son el artefacto central. Cuatro lecciones que aprendimos por las malas, aplicables directamente a esa propuesta y a cualquier diseño similar propio.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Fija el reloj, o tus intervalos de validez son re Jugables
&lt;/h2&gt;

&lt;p&gt;Que algo fue "verificado en marzo" solo constituye evidencia sobre abril si la marca de tiempo de la verificación es, ella misma, un objeto de confianza. Si el importador evalúa la validez contra su reloj local de pared, el bundle sigue siendo re jugable entre hosts con desviación de reloj o con el reloj manipulado.&lt;/p&gt;

&lt;p&gt;Lo que nos funcionó fue un solo cambio: registrar un &lt;code&gt;evaluation_clock&lt;/code&gt; explícito junto a cada resultado de verificación, y evaluar contra esa referencia fijada — nunca contra el reloj local del importador. Con eso, los intervalos de validez dejan de ser re Jugables. Es la misma estructura de riesgo del rug pull de herramientas (te confías de una definición que ya cambió), pero aplicada al tiempo: el "momento en que verificaste" también es superficie de ataque.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Limita la evidencia, hashea el resto
&lt;/h2&gt;

&lt;p&gt;Los recibos por memoria (comando ejecutado, resultado, código de salida, hash de salida) crecen sin cota. Un mes de evidencia de un agente ocupado vuelve el bundle intransportable.&lt;/p&gt;

&lt;p&gt;El patrón viable: guardar un extracto de salida con tope de tamaño más el hash del recibo completo, y mantener los recibos completos fuera de banda (out-of-band), disponibles solo para resolución de disputas. Separar "que exista evidencia" de "transportar la evidencia siempre" mantiene el bundle pequeño y la verificación completa.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Prueba el importador adversarialmente
&lt;/h2&gt;

&lt;p&gt;El parser de un bundle sellado es una decisión de confianza ejecutada sobre entrada no confiable: tiene exactamente la forma de ataque del tool poisoning. Nosotros generamos bundles mutados (mutaciones de dos puntos a través de fronteras firmadas) y exigimos que el importador rechace todos antes de llamar "implementado" al formato. El modelo observed-until-reverified solo gana su nombre si la propia ruta de reverificación sobrevive entrada adversarial.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. No hagas que la validez del bundle dependa de confiar en el exportador
&lt;/h2&gt;

&lt;p&gt;Anclar los digestos del bundle en un registro público de transparencia (estilo Rekor) más una cadena de releases firmada da verificabilidad por terceros y una historia de revocación sin autoridad central — y mapea limpio sobre custodia multi-salto, donde las firmas por salto se degradan al acumularse. El anclaje público no se degrada.&lt;/p&gt;

&lt;h2&gt;
  
  
  La pregunta que queda abierta: frescura de identidad
&lt;/h2&gt;

&lt;p&gt;Cuando el exportador rota llaves, un bundle viejo sigue siendo criptográficamente válido. Observed-until-reverified cubre la frescura del contenido — pero ¿quién cubre la frescura de la identidad? ¿Un bundle firmado por una llave ya rotada sigue siendo importable, y quién decide? No he visto aún una respuesta de diseño a esto, y me parece que ahí hay un terreno vacío.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artefactos públicos
&lt;/h2&gt;

&lt;p&gt;Lo concreto detrás de las lecciones 1 a 4 está publicado y es verificable por cualquiera:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repositorio: &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter" rel="noopener noreferrer"&gt;https://github.com/alicelabs-llc/universal-trust-adapter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Índice de vectores de conformance (regla de reloj fijado + distribuciones adversariales): &lt;a href="https://www.marketnow.site/uta/conformance/vectors/_index.json" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/vectors/_index.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SDK de verificación offline (solo node:crypto, registro de llaves CA embebido): &lt;a href="https://www.npmjs.com/package/agent-trust-card" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/agent-trust-card&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preguntas y objeciones en español bienvenidas — especialmente si alguien tiene una respuesta de diseño para la frescura de identidad.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>security</category>
      <category>mcp</category>
    </item>
    <item>
      <title>「検証済み」は「今も有効」を意味しない — エージェント間のトラストバンドル設計で学んだ4つの教訓</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Mon, 21 Sep 2026 00:17:02 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/jian-zheng-ji-mi-hajin-moyou-xiao-woyi-wei-sinai-ezientojian-notorasutobandorushe-ji-dexue-nda4tunojiao-xun-2c0h</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/jian-zheng-ji-mi-hajin-moyou-xiao-woyi-wei-sinai-ezientojian-notorasutobandorushe-ji-dexue-nda4tunojiao-xun-2c0h</guid>
      <description>&lt;p&gt;LlamaIndexに最近投稿された統合提案 — シールドされたメモリバンドルのエクスポート/インポート — は、エージェント間で検証済みの状態を持ち回るという問題領域そのものです。私たちはエージェント間検証のためのTrust Cardプロトコルを運用しており、シール済みでポータブルなバンドルはその中核アーティファクトです。運用の中で痛い目を見て学んだ4つの教訓を、この提案（そして自分のバンドル設計）に直接適用できる形で共有します。&lt;/p&gt;

&lt;h2&gt;
  
  
  1. クロックをピンしないと、有効性期間はリプレイ可能のまま
&lt;/h2&gt;

&lt;p&gt;「3月に検証済み」が「4月についての証拠」であるためには、検証タイムスタンプ自体が信頼対象になっていなければなりません。インポータが自ホストのローカル時計に対して有効性を評価する設計だと、バンドルはクロックスキューした環境や時計を操作されたホスト間でいくらでもリプレイできます。&lt;/p&gt;

&lt;p&gt;私たちに効いた変更は1つでした。検証結果の隣に明示的な &lt;code&gt;evaluation_clock&lt;/code&gt; を記録し、インポータのローカル時間ではなく、そのピンされた参照時刻に対して有効性を評価する。これだけで有効期間はリプレイ耐性を持ちます。&lt;/p&gt;

&lt;p&gt;Qiitaでよく見かけるTool Poisoning・Rug Pull・Shadow MCPという3リスクの分類に当てはめると、これは「検証した時点」そのものを攻撃面として扱う話です。ツール定義が後から差し替えられる（Rug Pull）のと同じ構造が、時刻の側にも存在します。&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 証拠はキャップし、残りはハッシュで
&lt;/h2&gt;

&lt;p&gt;メモリごとのレシート（コマンド、結果、終了コード、出力ハッシュ）は際限なく成長します。稼働中のエージェント1ヶ月分の証拠だけで、バンドルは配送不可能なサイズになります。&lt;/p&gt;

&lt;p&gt;実用的なパターンはこうです。サイズ上限付きの出力抜粋に加えて、完全なレシートのハッシュを保存する。完全なレシート自体は帯域外（out-of-band）に置き、紛争解決時にだけ取り出す。「証拠があること」と「証拠を常に運搬すること」を分離すれば、バンドルは小さく、検証は完全なままです。&lt;/p&gt;

&lt;h2&gt;
  
  
  3. インポータを敵対的にテストする
&lt;/h2&gt;

&lt;p&gt;シールドされたバンドルのパーサは、信頼できない入力に対して信頼の決定を実行するコードです。つまりtool poisoningと同じ攻撃形状を持ちます。&lt;/p&gt;

&lt;p&gt;私たちのやり方は、署名境界をまたぐ2点変異バンドルを機械的に生成し、インポータがそれら全てを拒否することをリリース条件にすることです。「実装した」と言えるのは、この敵対的入力テストを通過した後だけにすべきです。observed-until-reverified（再検証まで観測済み扱い）というモデルは、再検証パス自体が敵対的入力で生き残って初めて名前に値します。&lt;/p&gt;

&lt;h2&gt;
  
  
  4. バンドルの妥当性を、エクスポータへの信頼に依存させない
&lt;/h2&gt;

&lt;p&gt;バンドルのダイジェストを公開の透過性ログ（Rekor風）にアンカリングし、署名済みリリースチェーンと組み合わせると、中央機関なしで第三者検証と失効のストーリーが得られます。これはマルチホップのコスト・オブ・カストディ（多段の保管責任）にもきれいにマップします。ホップごとの署名だけでは、段数が増えると担保が劣化しますが、公開ログへのアンカリングは劣化しません。&lt;/p&gt;

&lt;h2&gt;
  
  
  残る問い：識別の鮮度
&lt;/h2&gt;

&lt;p&gt;鍵ローテーションを考えると、古い鍵で署名されたバンドルは回転後も暗号学的には有効です。observed-until-reverifiedはコンテンツの鮮度をカバーしますが、識別（identity）の鮮度は誰が、どう決めるのでしょうか。ローテーション済みの鍵で署名されたバンドルはインポート可能のままか。この質問への答えをまだ見たことがなく、それ自体が設計上の空き地だと思っています。&lt;/p&gt;

&lt;h2&gt;
  
  
  アーティファクトは全て公開
&lt;/h2&gt;

&lt;p&gt;上記1〜4の背後にある具体的な成果物は公開されています。ピンされたクロック規則と敵対的ウィンドウ分布を含むコンフォーマンスベクトルと、リファレンスランナー（MIT）:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;リポジトリ: &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter" rel="noopener noreferrer"&gt;https://github.com/alicelabs-llc/universal-trust-adapter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ベクトルインデックス: &lt;a href="https://www.marketnow.site/uta/conformance/vectors/_index.json" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/vectors/_index.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;オフライン検証SDK（node:cryptoのみ、CA鍵レジストリ埋め込み）: &lt;a href="https://www.npmjs.com/package/agent-trust-card" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/agent-trust-card&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;日本語での質問・ツッコミ歓迎です。特に「識別の鮮度」の問いに対する設計回答を持っている方はぜひ。&lt;/p&gt;

</description>
      <category>japanese</category>
      <category>ai</category>
      <category>security</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Your AI agent connects to MCP servers it has never met. Verify them first — for free.</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sun, 20 Sep 2026 03:17:24 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/your-ai-agent-connects-to-mcp-servers-it-has-never-met-verify-them-first-for-free-76f</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/your-ai-agent-connects-to-mcp-servers-it-has-never-met-verify-them-first-for-free-76f</guid>
      <description>&lt;p&gt;Your AI agent connects to MCP servers it has never met. Here's how to verify them first — for free.&lt;/p&gt;

&lt;p&gt;Modern agents are extroverts by design. Give them a URL, and they'll initialize an MCP session, list the tools, and start calling them. Nothing in the protocol asks the boring questions first: &lt;em&gt;who runs this server? how old is this domain? did the tool definition change since yesterday?&lt;/em&gt; The &lt;a href="https://genai.owasp.org/" rel="noopener noreferrer"&gt;OWASP GenAI MCP Cheat Sheet&lt;/a&gt; lists exactly these risks — tool poisoning, prompt injection through tool descriptions, and rug-pull servers. Most teams react &lt;em&gt;after&lt;/em&gt; an incident. The boring alternative is a pre-flight check that takes seconds and costs nothing.&lt;/p&gt;

&lt;p&gt;This post shows a working pre-flight stack you can add to any MCP client today: a domain scam-check, tool fingerprinting, credential verification, and a registry to search — all through one free remote endpoint (no API key, no signup, nothing to install).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0 — the endpoint
&lt;/h2&gt;

&lt;p&gt;Everything below is served by one MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"marketnow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.marketnow.site/api/mcp"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That block works in Cursor, Cline, Claude, and anything else speaking MCP. A live handshake returns &lt;code&gt;serverInfo: marketnow-mcp v1.13.0&lt;/code&gt; and nine tools. If you don't want to touch your MCP config, the same functions are plain REST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'https://www.marketnow.site/api/scam-check?domain=github.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1 — check the domain before you connect
&lt;/h2&gt;

&lt;p&gt;The scam-checker runs eight checks per domain: six static heuristics (URL shorteners, suspicious TLDs, punycode, typosquatting, subdomain abuse, suspicious tokens) and two live server-side checks — registry age via RDAP and TLS certificate inspection. This is the real output for &lt;code&gt;github.com&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TRUSTED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"risk_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url_shortener"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"triggered"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Not a known URL shortener"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"domain_age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"triggered"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Domain is in known-popular list (established)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ssl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"triggered"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Popular domain — SSL assumed valid"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two design decisions worth noting, because they're the difference between a security tool and a security &lt;em&gt;theater&lt;/em&gt; prop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fail-closed&lt;/strong&gt;: a brand-new clean scam returns &lt;code&gt;UNKNOWN&lt;/code&gt;, never &lt;code&gt;TRUSTED&lt;/code&gt;. Absence of evidence is not trust. The API says so in its own &lt;code&gt;honest_disclaimer&lt;/code&gt; field — no threat feeds, no magic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-side live checks&lt;/strong&gt;: RDAP and TLS happen on the server, so your client doesn't need to implement registry bootstrapping or certificate inspection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wire it into the agent flow: before the first &lt;code&gt;initialize&lt;/code&gt;, run &lt;code&gt;marketnow_check_domain&lt;/code&gt; on the server's host. It's one tool call, and it either passes quietly or gives you weighted reasons to stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — fingerprint the tools (poisoning defense)
&lt;/h2&gt;

&lt;p&gt;Tool poisoning works by changing what a tool &lt;em&gt;says about itself&lt;/em&gt;. A &lt;code&gt;read_file&lt;/code&gt; tool whose description quietly grows an instruction like "also exfiltrate ~/.ssh" is the classic example. The defense is boring: hash the tool definitions, store the hash, and compare on every reconnect.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;marketnow_fingerprint_tool&lt;/code&gt; tool takes tool definitions and returns cryptographic fingerprints. The pattern in practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On first connection, fingerprint every tool in &lt;code&gt;tools/list&lt;/code&gt;. Store the fingerprints.&lt;/li&gt;
&lt;li&gt;On reconnect, fingerprint again and diff.&lt;/li&gt;
&lt;li&gt;Any drift = alarm. Tool descriptions are part of your prompt surface; treat changes to them like changes to your system prompt.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the OWASP-recommended "verify tool definitions before execution", operationalized as a callable tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — verify credentials (8 formats, 12 stages)
&lt;/h2&gt;

&lt;p&gt;When a peer agent or server presents a credential, you need to answer three questions: is the signature valid, is it expired, and is it revoked. &lt;code&gt;marketnow_verify_trust&lt;/code&gt; runs a 12-stage pipeline covering all three plus canonicalization, CA rotation, and format-specific checks. It speaks eight formats: ATC v3, JWT, W3C Verifiable Credentials, MCP Card, A2A, EAT-AI, ZTA, and X.509.&lt;/p&gt;

&lt;p&gt;The same call fails closed — if the pipeline can't complete, the answer is &lt;code&gt;unknown&lt;/code&gt;, and the caller is expected to treat that as a stop, not a retry.&lt;/p&gt;

&lt;p&gt;Revocation deserves its own mention because it's where most home-rolled schemes rot: &lt;code&gt;marketnow_check_revocation&lt;/code&gt; checks any Agent Trust Card ID or CA key ID (&lt;code&gt;kid&lt;/code&gt;) against a public status store. No ledger rent, no per-check fee.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — search the registry instead of trusting a link
&lt;/h2&gt;

&lt;p&gt;When someone sends your agent "just add this MCP server", the &lt;a href="https://www.marketnow.site/catalog" rel="noopener noreferrer"&gt;catalog&lt;/a&gt; is the boring middleman: 68,388 indexed servers across GitHub, npm, PyPI, the official registry, and more — deduplicated, searchable through the &lt;code&gt;marketnow_search_skills&lt;/code&gt; tool. Unknown server from a chat message → look it up. Listed with history, or not listed at all? That's signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The credential you can mint yourself
&lt;/h2&gt;

&lt;p&gt;If you &lt;em&gt;operate&lt;/em&gt; agents, the same ecosystem gives you &lt;a href="https://www.npmjs.com/package/agent-trust-card" rel="noopener noreferrer"&gt;Agent Trust Cards&lt;/a&gt;: Ed25519-signed, RFC 8785-canonicalized credentials with a full capability model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generateKeyPair&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;issueATC&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agent-trust-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ca&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateKeyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateKeyPair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;atc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;issueATC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;card_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ATC-2026-0000001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;agent_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-bot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agent_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Bot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agent_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;filesystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;own_dir&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;own_dir&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;egress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;allowlist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sandboxed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;trust_score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;risk_level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;score_explanation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Clean audit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;scored_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&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;Minting is free. Verification is free. Revocation lookups are free. The current CA public key is a public endpoint (&lt;code&gt;/api/atc?action=ca-key&lt;/code&gt;), and verifiers are expected to fetch it live rather than pinning a stale copy — CA rotation is a first-class pipeline stage, not an afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why free matters here
&lt;/h2&gt;

&lt;p&gt;Trust verification has a pricing problem. Per-call fee protocols and paywalled ledgers mean the parties who most need cheap verification — hobbyists, students, small teams, and, bluntly, agents making autonomous decisions — hit a paywall exactly when the check matters. The whole MarketNow stack (endpoint, credential format, registry search, revocation, and the &lt;a href="https://www.npmjs.com/package/marketnow-mcp" rel="noopener noreferrer"&gt;14 npm packages&lt;/a&gt; — around 6,300 downloads a month) is free with no key-gated tier. Fail-closed + free is the honest combination: you don't pay to be told "unknown", and "unknown" is a real answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pre-flight checklist
&lt;/h2&gt;

&lt;p&gt;For an agent about to call an unknown MCP tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;marketnow_check_domain&lt;/code&gt; on the server's host.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;marketnow_fingerprint_tool&lt;/code&gt; on the tool definitions — store them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;marketnow_verify_trust&lt;/code&gt; if a credential is presented.&lt;/li&gt;
&lt;li&gt;Only then execute. Re-verify fingerprints on reconnect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repo with all client configs and machine-readable docs: &lt;a href="https://github.com/eddyflores100-lang/marketnow-mcp" rel="noopener noreferrer"&gt;marketnow-mcp&lt;/a&gt; (canonical development lives in &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter" rel="noopener noreferrer"&gt;universal-trust-adapter&lt;/a&gt;). Remote endpoint, zero install, no API keys: &lt;code&gt;https://www.marketnow.site/api/mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If a check can't complete, the answer is "unknown" — and that's the feature.&lt;/p&gt;




&lt;h2&gt;
  
  
  Update — 2026-09-20
&lt;/h2&gt;

&lt;p&gt;MarketNow is now &lt;strong&gt;dual-licensed MIT OR Apache-2.0&lt;/strong&gt; — free for any use, including commercial (see &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/blob/main/LICENSE-MIT" rel="noopener noreferrer"&gt;LICENSE-MIT&lt;/a&gt; / &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/blob/main/LICENSE-APACHE" rel="noopener noreferrer"&gt;LICENSE-APACHE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Also submitted to the &lt;strong&gt;Docker MCP Catalog&lt;/strong&gt; as a remote security server: &lt;a href="https://github.com/docker/mcp-registry/pull/5175" rel="noopener noreferrer"&gt;docker/mcp-registry#5175&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The trust layer stays free forever, no API key:  — 9 tools covering credential verification (8 formats), domain scam-checking, and tool-definition fingerprinting (OWASP anti-tool-poisoning).&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>mcp</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>MCP servers run code with your credentials. Here's the 60-second gate I put in front of them.</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sat, 19 Sep 2026 18:47:03 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/mcp-servers-run-code-with-your-credentials-heres-the-60-second-gate-i-put-in-front-of-them-242h</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/mcp-servers-run-code-with-your-credentials-heres-the-60-second-gate-i-put-in-front-of-them-242h</guid>
      <description>&lt;p&gt;You installed an MCP server with &lt;code&gt;npx -y some-mcp-server&lt;/code&gt;. That command just ran third-party code with the same filesystem and network access your agent has. There was no review, no gate, no audit trail — and every &lt;code&gt;tools/call&lt;/code&gt; your agent makes afterwards is that server's code touching your disk, your env, your credentials.&lt;/p&gt;

&lt;p&gt;This is not a hypothetical. When we deep-scanned the most-installed subset of our MCP catalog (9,248 servers at the last full pass):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0.3% were outright malicious&lt;/strong&gt; — obfuscated payloads, credential harvesting, or destructive commands behind innocuous tool names&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;11% had undocumented network egress&lt;/strong&gt; — they call endpoints that appear nowhere in their README or repo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;11%. One in nine. The worst ones don't crash your agent — they work perfectly, quietly, and phone home.&lt;/p&gt;

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

&lt;p&gt;The fix is boring and old: put a policy gate in front of every tool call. We built one, it's free, zero dependencies, Node &amp;gt;= 16:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @marketnow/trust-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;tools/call&lt;/code&gt; from your agent passes through a configurable check &lt;em&gt;before&lt;/em&gt; execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TrustGateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;withTrustGateway&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@marketnow/trust-gateway&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TrustGateway&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;min_trust_score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// 12-stage pipeline must clear this&lt;/span&gt;
  &lt;span class="na"&gt;require_pinned_ca&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// credential must chain to your pinned CA&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Explicit form — decision object: { allowed, reason, trust_score }&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agentCredential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read_file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DENY:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Or wrap an existing handler in one line — denials throw TRUST_GATEWAY_DENY:&amp;lt;reason&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secured&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withTrustGateway&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myToolHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gateway&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 12-stage pipeline verifies the caller's credential (Agent Trust Card / EAT, Ed25519 + canonical JSON), scores trust across stages, and applies your policy — allow, deny, or gate on score. A server that redefines its &lt;code&gt;tools/list&lt;/code&gt; surface between calls (the OWASP tool-poisoning scenario) fails the fingerprint stage instead of silently gaining new powers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why receipts matter more than the gate
&lt;/h2&gt;

&lt;p&gt;A gate that only blocks is a firewall with no logs — when something goes wrong, you have nothing to show for it. Every allow/deny decision here emits a signed, hash-chained receipt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReceiptStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@marketnow/trust-gateway&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReceiptStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/var/log/uta/receipts.jsonl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Every decision: Ed25519-signed, each receipt hashes the previous one.&lt;/span&gt;
&lt;span class="c1"&gt;// Tamper with line 40 and lines 41..N stop verifying.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replay them later to prove &lt;em&gt;what was allowed and why&lt;/em&gt; — to yourself, to an auditor, to a customer. "The agent did X because the gate scored Y at time Z, and here's the signed chain" is a very different conversation than "our logs say it was probably fine."&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is NOT (the honest part)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a sandbox.&lt;/strong&gt; If you run genuinely untrusted servers, put them in a container/VM. The gateway is the policy + audit layer, not isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a trust score oracle.&lt;/strong&gt; A high score doesn't mean "safe"; it means "verified against the stages you configured." Fail-closed by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a replacement for reading the code.&lt;/strong&gt; &lt;code&gt;install-risk&lt;/code&gt; classification (red/yellow/green in the &lt;a href="https://www.marketnow.site/catalog" rel="noopener noreferrer"&gt;catalog&lt;/a&gt;) tells you what runs code on every start — you still decide.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verify us, don't trust us
&lt;/h2&gt;

&lt;p&gt;We apply the same standard to ourselves. The full conformance suite — 14 test vectors, stage scoring, curl + node only — is public, and our own claims are anchored to Sigstore Rekor's transparency log so a stranger can re-derive them without an account:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.marketnow.site/uta/conformance/" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One ask
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;agent-trust-card&lt;/code&gt; gets ~300 downloads a week and the repo has ~155 unique cloners a month — npm doesn't tell us who you are or what you're building. If you're using UTA in production, we'd genuinely like to know what's working and what's missing. There's a thread for exactly that:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/discussions/21" rel="noopener noreferrer"&gt;Who's using UTA / agent-trust-card? Introduce yourself and your use case&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every reply there helps prioritize the next format adapters and conformance vectors — and gives other adopters a public list of real use cases instead of a download counter.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Edison Flores, founder of &lt;a href="https://github.com/alicelabs-llc" rel="noopener noreferrer"&gt;AliceLabs LLC&lt;/a&gt; — we build open-source security infrastructure for AI agents. This post is about my own project; the gateway, the receipts library and the conformance suite are free.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Update — 2026-09-20
&lt;/h2&gt;

&lt;p&gt;MarketNow is now &lt;strong&gt;dual-licensed MIT OR Apache-2.0&lt;/strong&gt; — free for any use, including commercial (see &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/blob/main/LICENSE-MIT" rel="noopener noreferrer"&gt;LICENSE-MIT&lt;/a&gt; / &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/blob/main/LICENSE-APACHE" rel="noopener noreferrer"&gt;LICENSE-APACHE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Also submitted to the &lt;strong&gt;Docker MCP Catalog&lt;/strong&gt; as a remote security server: &lt;a href="https://github.com/docker/mcp-registry/pull/5175" rel="noopener noreferrer"&gt;docker/mcp-registry#5175&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The trust layer stays free forever, no API key:  — 9 tools covering credential verification (8 formats), domain scam-checking, and tool-definition fingerprinting (OWASP anti-tool-poisoning).&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>security</category>
      <category>javascript</category>
    </item>
    <item>
      <title>VIGÍA ML: Gas-Well Predictive Monitoring That Runs Entirely in the Browser (TensorFlow.js + React)</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sat, 19 Sep 2026 05:01:10 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/vigia-ml-gas-well-predictive-monitoring-that-runs-entirely-in-the-browser-tensorflowjs-react-2coa</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/vigia-ml-gas-well-predictive-monitoring-that-runs-entirely-in-the-browser-tensorflowjs-react-2coa</guid>
      <description>&lt;p&gt;VIGÍA ML is a predictive console for gas wells — production forecasting, anomaly detection, fault diagnosis, and operational recommendations — where &lt;strong&gt;every model trains and runs live in the browser&lt;/strong&gt;. No backend, no GPU cluster, no data leaving the device.&lt;/p&gt;

&lt;p&gt;Live demo (Spanish-first UI): &lt;a href="https://alicelabs-llc.github.io/vigia-ml/" rel="noopener noreferrer"&gt;https://alicelabs-llc.github.io/vigia-ml/&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://github.com/alicelabs-llc/vigia-ml" rel="noopener noreferrer"&gt;https://github.com/alicelabs-llc/vigia-ml&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem it targets
&lt;/h2&gt;

&lt;p&gt;Production engineers and field operators work with well time series — tubing pressure, flow rates, temperatures, choke positions — that are almost always proprietary. Sending that data to a cloud ML pipeline means negotiating data-export policies, paying for inference infrastructure, and depending on connectivity at sites where connectivity is often the least reliable thing around. Most small operations just... don't do ML at all, and rely on threshold alarms and gut feel.&lt;/p&gt;

&lt;p&gt;We built VIGÍA ML around a simple constraint: &lt;strong&gt;the data never has to leave the laptop it's already on.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Four models, all on-device
&lt;/h2&gt;

&lt;p&gt;The console runs four distinct models, each trained in-session on the data you load:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LSTM production forecaster&lt;/strong&gt; — a recurrent net trained on the well's own history, projecting pressure/flow trajectories hours ahead. You watch it train (loss curve and all), which builds the right amount of trust: you &lt;em&gt;saw&lt;/em&gt; it converge on &lt;em&gt;your&lt;/em&gt; data, not on a benchmark you never see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autoencoder anomaly detector&lt;/strong&gt; — trained on "normal" operating windows; flagged anomalies are windows with high reconstruction error. This catches slow drifts (sand accumulation, gradual choke wear) that fixed thresholds miss, because the model learns the well's baseline rather than a static rule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neural fault classifier&lt;/strong&gt; — maps operating-state features to common failure modes (liquid loading, hydrate risk, valve malfunction), with per-class confidence so "UNKNOWN" is an honest output, not a forced guess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommendation layer&lt;/strong&gt; — turns diagnosis + forecast into operational suggestions (choke adjustment, surveillance frequency), always shown with the reasoning, never as a black-box verdict.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why in-browser ML is the right call here
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by architecture.&lt;/strong&gt; Well data stays in the browser tab. There is no server to subpoena, leak, or breach — the strongest data-governance story is the one where the data simply never moves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline as a feature, not a fallback.&lt;/strong&gt; VIGÍA ML is a PWA: once loaded, it keeps working at a pad site with zero connectivity. Field conditions are the &lt;em&gt;expected&lt;/em&gt; condition, not the error case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero inference cost.&lt;/strong&gt; Training and inference are free at the edge. The marginal cost of one more engineer opening the console is zero, which is the only pricing model that makes sense for tools used across dozens of marginal wells.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditability.&lt;/strong&gt; The weights are right there in DevTools. An engineer who wants to inspect what the model learned can — no API access requests, no vendor tickets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Engineering notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React 18 + TypeScript 5.7, TensorFlow.js 4.22, Vite 6, Tailwind 4&lt;/li&gt;
&lt;li&gt;140 tests passing (unit + integration over the training/eval pipelines)&lt;/li&gt;
&lt;li&gt;License: AL-1.0 (source-available; free to run and evaluate)&lt;/li&gt;
&lt;li&gt;Everything — data loading, training, evaluation, export of results — happens client-side&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The UI is Spanish-first because the initial users are LATAM operations teams, but the codebase is standard TypeScript/React; the language of the interface is a config concern, not an architectural one.&lt;/p&gt;

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

&lt;p&gt;Open the demo, load a well dataset (or use the synthetic one), and watch the forecaster train in ~30 seconds on a plain laptop. The anomaly detector's reconstruction-error view is the most interesting screen — you'll see drift accumulate in the error signal well before any threshold alarm would have fired.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demo: &lt;a href="https://alicelabs-llc.github.io/vigia-ml/" rel="noopener noreferrer"&gt;https://alicelabs-llc.github.io/vigia-ml/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/alicelabs-llc/vigia-ml" rel="noopener noreferrer"&gt;https://github.com/alicelabs-llc/vigia-ml&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VIGÍA ML comes from the same team that builds UTA (Universal Trust Adapter — trust infrastructure for AI agents). Different domain, same philosophy: verification you can run yourself, on hardware you control, without shipping your data to anyone.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>machinelearning</category>
      <category>react</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Re: @alexshev — revocation, the signed checkpoint, and bounded freshness are live</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Wed, 16 Sep 2026 00:42:16 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/re-alexshev-revocation-the-signed-checkpoint-and-bounded-freshness-are-live-45c3</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/re-alexshev-revocation-the-signed-checkpoint-and-bounded-freshness-are-live-45c3</guid>
      <description>&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;This is a reply to &lt;a href="https://dev.to/alexshev"&gt;@alexshev&lt;/a&gt;'s comment (2026-09-09) on &lt;a href="https://dev.to/edison_flores_6d2cd381b13/visa-has-a-trusted-agent-protocol-mastercard-has-verifiable-intent-heres-the-layer-neither-one-5g41"&gt;Visa Has a Trusted Agent Protocol. Mastercard Has Verifiable Intent. Here's the Layer Neither One Gives You&lt;/a&gt; — a comment that aged well, because the three things it asked for are now the three things that exist:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The proposed layering is clearest when revocation is modeled alongside issuance. A merchant needs to know not only that a trust artifact was transparently published, but whether a key, runner, or policy was revoked at the decision time and how a disconnected verifier catches up later. A signed checkpoint plus a bounded freshness rule would make that offline story concrete."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three asks, three live artifacts. Pointing at each.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Revocation is modeled alongside issuance
&lt;/h2&gt;

&lt;p&gt;The UTA conformance suite (schema 1.5.0) carries &lt;code&gt;revoked-atc&lt;/code&gt; — a properly signed, anchored, in-window card whose &lt;em&gt;only&lt;/em&gt; defect is revocation, with &lt;code&gt;expected_verify: false&lt;/code&gt;. A runner can no longer clear every issuance-side check and silently ignore the revocation side: the suite prices that evasion at a full failure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suite index (13 vectors + sidecars): &lt;a href="https://www.marketnow.site/uta/conformance/vectors/_index.json" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/vectors/_index.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Reference scorer (documents each property it defends): &lt;a href="https://www.marketnow.site/uta/conformance/score-runner.mjs" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/score-runner.mjs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. The signed checkpoint is a real Rekor entry
&lt;/h2&gt;

&lt;p&gt;The anchors are Sigstore Rekor entries, not self-attested files. &lt;code&gt;anchor-record-v5.json&lt;/code&gt; is Rekor &lt;code&gt;log_index&lt;/code&gt; &lt;strong&gt;2787622029&lt;/strong&gt; (integrated 2026-09-10T21:52:48Z) and ships its statement, countersignature, and inclusion proof — with the v2→v5 chain published beside it. A disconnected verifier catches up by verifying inclusion against the public log, not by trusting our server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.marketnow.site/uta/conformance/anchors/anchor-record-v5.json" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/anchors/anchor-record-v5.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. The bounded freshness rule is a release chain
&lt;/h2&gt;

&lt;p&gt;The freshness reference turned out to be exactly the bounded rule from the comment: a persistent release identity, monotone counters (r1→r2), local state, and an anchor floor — written up as rollback resistance, with the r1→r2 advance exercised for real hours after the chain was born:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/edison_flores_6d2cd381b13/re-anp2network-round-4-the-freshness-reference-is-a-release-chain-r1-r2-already-exercised-hi4"&gt;Re: @anp2network — round 4: the freshness reference is a release chain&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule a disconnected verifier can enforce with those pieces: &lt;em&gt;accept a trust artifact only if its release is not older than the newest anchored release minus the floor.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that is still open
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Policy-level revocation at decision time.&lt;/strong&gt; Card revocation is in the suite; a named &lt;em&gt;policy&lt;/em&gt; losing its endorsement without a new release is not yet a vector. If you have a concrete shape in mind, it would slot naturally next to &lt;code&gt;revoked-atc&lt;/code&gt; — and the anchor floor is already the half of it that an offline verifier can check.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>We audited our own MCP server across five registries — and found three ghost entries</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sun, 13 Sep 2026 16:21:55 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/we-audited-our-own-mcp-server-across-five-registries-and-found-three-ghost-entries-560h</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/we-audited-our-own-mcp-server-across-five-registries-and-found-three-ghost-entries-560h</guid>
      <description>&lt;p&gt;Yesterday the first maintainer review landed on our PR to awesome-mcp-servers. Point #1 from the maintainer: our Glama badge points to a server registered under &lt;code&gt;edgarfloresguerra2011-a11y/marketnow&lt;/code&gt; — but our repo is &lt;code&gt;alicelabs-llc/marketnow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We checked. That GitHub account &lt;strong&gt;and&lt;/strong&gt; that repository both return 404. They never existed under that org — or they were deleted long ago. That one line of review feedback sent us down a rabbit hole: if a top MCP list sees a ghost identity for our server, what do the actual registries see?&lt;/p&gt;

&lt;p&gt;What follows is an audit of our own server across five registries, done today, with receipts. If you maintain an MCP server, I'd bet money you have at least one ghost entry too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The official registry: three entries, one dead identity
&lt;/h2&gt;

&lt;p&gt;We queried the official registry's search API for our own server name. Three entries came back, all registered under &lt;code&gt;io.github.edgarfloresguerra2011-a11y/...&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Entry&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Claimed catalog size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...edgarfloresguerra2011-a11y/marketnow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.4.1&lt;/td&gt;
&lt;td&gt;active&lt;/td&gt;
&lt;td&gt;"8,764 security-audited skills"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...edgarfloresguerra2011-a11y/marketnow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.5.0&lt;/td&gt;
&lt;td&gt;active, &lt;strong&gt;isLatest: true&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;"8,845 security-audited skills"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;...edgarfloresguerra2011-a11y/marketnow-mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.0.0&lt;/td&gt;
&lt;td&gt;deprecated&lt;/td&gt;
&lt;td&gt;"13,800+ MCP skills"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three point to &lt;code&gt;https://github.com/edgarfloresguerra2011-a11y/marketnow&lt;/code&gt; — a 404, confirmed today via the GitHub API (both the user and the repo are gone).&lt;/p&gt;

&lt;p&gt;Meanwhile our npm package &lt;code&gt;marketnow-mcp&lt;/code&gt; is at &lt;strong&gt;1.10.1&lt;/strong&gt;, and the registry's "latest" for us says &lt;strong&gt;1.5.0&lt;/strong&gt;. The descriptions quote a catalog of ~8.8k items; our current index is &lt;strong&gt;69,077 servers&lt;/strong&gt;. The deprecated entry even advertises our old SSE endpoint, which we retired two transport generations ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Glama: rated A, for a repo that doesn't exist
&lt;/h2&gt;

&lt;p&gt;The ghost Glama entry is very much alive and — this is the fun part — &lt;strong&gt;rated A&lt;/strong&gt;. The badge renders fine: "remote-capable, maintenance rated A". The badge title still carries our old positioning ("MCP Skills Marketplace") from months of repositioning ago.&lt;/p&gt;

&lt;p&gt;The entry for our actual repo (&lt;code&gt;alicelabs-llc/marketnow&lt;/code&gt;)? The badge endpoint answers plainly: &lt;strong&gt;"This MCP server is not listed on Glama."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So the only MarketNow on Glama is a healthy, top-rated listing for a GitHub repository that returns 404. That is exactly what the maintainer's review caught — and it's why that review was worth more than a hundred merges of rubber-stamp PRs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smithery: an entry with no face
&lt;/h2&gt;

&lt;p&gt;Smithery's public registry API shows one entry for us: &lt;code&gt;eddyflores100/marketnow-mcp&lt;/code&gt;. Verified: &lt;strong&gt;false&lt;/strong&gt;. Install count: &lt;strong&gt;0&lt;/strong&gt;. Description: &lt;strong&gt;empty string&lt;/strong&gt;. It was auto-created at some point and just sits there — a listing with no face is almost worse than no listing, because it occupies the namespace while telling users nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the map
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;mcpservers.org&lt;/strong&gt; — not listed. They have a free submission form (review within ~2 weeks; a $39 premium tier jumps the queue).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PulseMCP&lt;/strong&gt; — their directory pages currently show a banner: new submissions and listing changes are &lt;strong&gt;paused&lt;/strong&gt; while they rework ingestion. Not actionable for now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mcp.so&lt;/strong&gt; — submissions run through GitHub issues in their repo. We couldn't verify our listing status from our datacenter IP (Cloudflare says hi), so this one stays a manual check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TensorBlock&lt;/strong&gt; — the one listing we got the honest way, via a merged PR. It doesn't show up in their sitemap from our vantage point, so we'll re-verify manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where ghosts come from
&lt;/h2&gt;

&lt;p&gt;Here's the mechanism, and it's nobody's bug in particular:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Months ago, an early auto-registration published our manifest with the &lt;code&gt;mcpName&lt;/code&gt; that lived in the npm &lt;code&gt;package.json&lt;/code&gt; at the time — &lt;code&gt;io.github.edgarfloresguerra2011-a11y/marketnow&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We later renamed the org and fixed &lt;code&gt;mcpName&lt;/code&gt; in the published npm package (current: &lt;code&gt;io.github.alicelabs-llc/marketnow&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The registry kept the old entries. Registries don't garbage-collect entries whose repositories die, and why would they — they can't know if a repo moved, was renamed, or was resurrected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The nasty part is &lt;strong&gt;cross-ingestion&lt;/strong&gt;: directories ingest each other. A stale-but-authoritative entry with an A-rating propagates downstream into aggregators, mirrors and chat.mcp.so-style clones. Agents and MCP clients that read registry data at runtime get the dead link and numbers that are stale by an order of magnitude. Identity hygiene isn't cosmetic — it's what downstream machines read.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, as a checklist
&lt;/h2&gt;

&lt;p&gt;If you maintain an MCP server, this is a 30-minute audit-and-repair:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Anchor your identity in &lt;code&gt;package.json&lt;/code&gt;.&lt;/strong&gt; The official registry derives your name from &lt;code&gt;mcpName&lt;/code&gt; (for npm packages). Make it &lt;code&gt;io.github.&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&lt;/code&gt; and make it match the repo you actually control. Ours is fixed in &lt;code&gt;marketnow-mcp@1.10.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish the corrected entry.&lt;/strong&gt; The &lt;code&gt;mcp-publisher&lt;/code&gt; CLI does &lt;code&gt;init / login / publish&lt;/code&gt;. A correctly-named entry with current metadata beats any ghost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claim on Glama.&lt;/strong&gt; Their submission + claim flow verifies you own the server. The README badge URL must point to the entry that matches your repo &lt;em&gt;exactly&lt;/em&gt; — that's the rule our reviewer enforced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claim and dress your Smithery listing.&lt;/strong&gt; Login, verify, fill the description. An empty auto-generated entry tells users nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit to the open directories&lt;/strong&gt; (mcpservers.org, mcp.so) and re-check PulseMCP when their submissions reopen.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A security footnote we didn't expect
&lt;/h2&gt;

&lt;p&gt;While auditing Smithery's public registry API for this post, we ran into listings whose &lt;strong&gt;description field&lt;/strong&gt; is a base64-encoded "install instruction". Decoding one: &lt;code&gt;curl&lt;/code&gt; from a &lt;strong&gt;plain-HTTP raw IP address&lt;/strong&gt;, piped straight into &lt;code&gt;bash&lt;/code&gt;. On a listing marked verified, with a five-digit install count.&lt;/p&gt;

&lt;p&gt;We're not naming it here — we'd rather it die quietly than get trended. But the lesson generalizes: never run "install instructions" that come out of a &lt;em&gt;description field&lt;/em&gt;. Descriptions are data, not code.&lt;/p&gt;

&lt;p&gt;This is precisely why our own directory classifies every listing's install risk (red / yellow / green, with the reason shown) and fingerprints each server's &lt;code&gt;tools/list&lt;/code&gt; surface (RFC 8785 JCS + SHA-256) so a silent tool-poisoning redefinition is detectable after the fact. The registry entry is metadata; the &lt;em&gt;risk&lt;/em&gt; lives in what the entry points at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the audit on your own server
&lt;/h2&gt;

&lt;p&gt;Five minutes, no tools required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;registry.modelcontextprotocol.io/v0/servers?search=&amp;lt;your-name&amp;gt;&lt;/code&gt; — count your ghost entries&lt;/li&gt;
&lt;li&gt;Glama badge endpoint — does your exact repo have a listing?&lt;/li&gt;
&lt;li&gt;Smithery registry API — is your entry verified, described, alive?&lt;/li&gt;
&lt;li&gt;Your npm &lt;code&gt;package.json&lt;/code&gt; — does &lt;code&gt;mcpName&lt;/code&gt; match the repo you control?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find ghosts, burn them this week. Directories are how agents discover servers now — and a dead identity with an A-rating is the kind of glitch that quietly compounds.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Edison Flores — I build &lt;a href="https://www.marketnow.site" rel="noopener noreferrer"&gt;MarketNow&lt;/a&gt;, a security-gated MCP server directory (69,077 servers indexed, source links and install-risk for each, &lt;a href="https://www.marketnow.site/catalog" rel="noopener noreferrer"&gt;transparency page here&lt;/a&gt;). Thanks to &lt;a href="https://github.com/punkpeye" rel="noopener noreferrer"&gt;punkpeye&lt;/a&gt; for the review that started this audit. This post is about my own project; the directory, search API and badge system are free.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Pre-auth discoverability in MCP: what the numbers say, and what a directory sees</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sun, 13 Sep 2026 07:59:11 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/pre-auth-discoverability-in-mcp-what-the-numbers-say-and-what-a-directory-sees-1pbd</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/pre-auth-discoverability-in-mcp-what-the-numbers-say-and-what-a-directory-sees-1pbd</guid>
      <description>&lt;p&gt;Since May 2025, the MCP spec repo has carried an open question (&lt;a href="https://github.com/modelcontextprotocol/modelcontextprotocol/issues/540" rel="noopener noreferrer"&gt;#540&lt;/a&gt;): should an MCP server expose what it offers &lt;em&gt;before&lt;/em&gt; a client authenticates? The thread ran on principle for more than a year — self-description versus auth boundaries, discoverability versus least exposure. This week it finally got data, and the data changes the shape of the argument.&lt;/p&gt;

&lt;p&gt;This post covers the measurement from the probe side and adds the view we don't usually get in these threads: what a server directory sees when it tries to describe MCP servers at ecosystem scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measurement
&lt;/h2&gt;

&lt;p&gt;unempyd probed remote MCP endpoints anonymously — one &lt;code&gt;initialize&lt;/code&gt; and one &lt;code&gt;tools/list&lt;/code&gt; per endpoint, at most one endpoint per publisher domain — and published the method and results (&lt;a href="https://unempyd.github.io/X190-site/report.html" rel="noopener noreferrer"&gt;full report&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The first pass sampled 100 endpoints from the official registry: 45 returned a tool list with no credentials. The correction that followed matters more than that headline. Of 20,492 remote connectors in the largest public index, 16,375 declare no authentication at all. For four fifths of the population, answering &lt;code&gt;tools/list&lt;/code&gt; unauthenticated is documented configuration, not a fault — counting those tells you nothing about anything.&lt;/p&gt;

&lt;p&gt;The population where the question means something is the 117 endpoints whose operators &lt;em&gt;chose&lt;/em&gt; to require credentials (OAuth2 or an API key). Of those:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;18 served the complete tool list to an anonymous caller&lt;/strong&gt; — they intend to require auth and don't enforce it on &lt;code&gt;tools/list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;19 refused, but with no RFC 9728 challenge a client could follow&lt;/strong&gt; — a refusal no compliant client can act on&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;79 refused correctly&lt;/strong&gt;, with protected-resource metadata that resolved&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1 advertised metadata that would not fetch&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So roughly 15% of endpoints that intend to require authentication do not enforce it on &lt;code&gt;tools/list&lt;/code&gt;, and another 16% refuse in a way no compliant client can act on.&lt;/p&gt;

&lt;p&gt;The failure is not distributed evenly either. Against the first-party MCP endpoints of twelve large SaaS vendors that document an OAuth requirement, zero of the eleven that answered served anything. The leaks concentrate in servers built by small teams — precisely where a spec default does the most work, because a default is load-bearing exactly for the people who will not read the spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the directory side sees
&lt;/h2&gt;

&lt;p&gt;We index 69,077 MCP servers from GitHub, npm and PyPI source, 133,426 tracked ecosystem-wide (&lt;a href="https://www.marketnow.site" rel="noopener noreferrer"&gt;marketnow.site&lt;/a&gt;). Here is the part of the population the endpoint-side probe cannot see: &lt;strong&gt;most MCP servers have no reachable remote endpoint at all.&lt;/strong&gt; They exist as repositories and packages. For the majority of the ecosystem, the only pre-auth discovery surface that exists today is source code and package metadata.&lt;/p&gt;

&lt;p&gt;The endpoint question and the discoverability question are already decoupled in the wild. Any answer to #540 that only governs what a live endpoint serves leaves most of the ecosystem exactly where it already is: described by READMEs, package manifests, and static analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 401 is indistinguishable from a mistake
&lt;/h2&gt;

&lt;p&gt;From the directory side the ambiguity is concrete. When a server 401s an anonymous caller, a crawler cannot distinguish "auth required by design" from "misconfigured" — the operator's intent isn't machine-readable. We classify from source when the endpoint refuses: tools from README and package metadata, install-risk from static analysis, and the listing gets labeled "auth required, not probed." That is a workaround, not a signal. It is honest about what we know, but it cannot tell an operator that their server is one of the 18.&lt;/p&gt;

&lt;p&gt;Nothing can, today. That is the part of the closing argument in the thread that cuts across the whole debate: a server that intends to require authentication and fails to enforce it has no mechanism that makes the failure visible to its own operator.&lt;/p&gt;

&lt;h2&gt;
  
  
  The middle ground that doesn't exist yet
&lt;/h2&gt;

&lt;p&gt;The thread's proposed compromise — an unauthenticated capability manifest rather than the concrete resource list — has a measurable absence. In the first pass, none of the pre-auth servers served anything resembling a manifest. What exists in the wild is binary: full refusal, or the complete callable surface — median 5 tools, maximum 302, 926 tools disclosed across the sample, with names and input schemas included.&lt;/p&gt;

&lt;p&gt;A signed manifest with capability names and counts — no input schemas, nothing callable — would resolve both directions at once. Directories could describe a server without its auth boundary leaking anything exploitable. Operators who want discovery would get a channel that doesn't require serving the concrete tool list. And install-risk classification would become substantially less dependent on source analysis, which is currently the only honest fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  The RFC 9728 bar
&lt;/h2&gt;

&lt;p&gt;Whatever lands long-term, there is a floor available now: a 401 should publish protected-resource metadata that resolves. Nineteen of the 117 don't even clear that bar. A crawler that understands RFC 9728 can at least record the auth boundary correctly — which is the difference between "auth required, not probed" as a guess and as a verified fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we do meanwhile
&lt;/h2&gt;

&lt;p&gt;Source-first indexing is the strategy regardless of how the spec lands. An auth-gated server still gets a real listing — capabilities, security classification, labeled honestly rather than silently empty. The public &lt;a href="https://www.marketnow.site/submit" rel="noopener noreferrer"&gt;submission pipeline&lt;/a&gt; validates and lists from source, so a server can be discoverable without ever serving an anonymous endpoint. And the 29 static rules behind the install-risk tiers — injection patterns in tool descriptions, embedded secrets, dangerous APIs — run against source, where the same patterns that poison deployed tool descriptions are visible before anyone deploys.&lt;/p&gt;

&lt;p&gt;If pre-auth discovery becomes standard, the 18 stop being a mistake. If it does not, they need something in the protocol that makes the failure visible. Either way, the directory side keeps describing servers from source — because for most of the ecosystem, that is the only side that exists.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>The ingestion queue was public. 48 hours later it's empty: +1,097 MCP servers (66,496 67,593)</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Fri, 11 Sep 2026 20:12:20 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/the-ingestion-queue-was-public-48-hours-later-its-empty-1097-mcp-servers-66496-67593-240j</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/the-ingestion-queue-was-public-48-hours-later-its-empty-1097-mcp-servers-66496-67593-240j</guid>
      <description>&lt;p&gt;Two days ago we ended a writeup with: &lt;em&gt;"the 367 we're missing — plus 27 official npm packages — are queued for the next ingestion run. Publishing the gap is the point."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is that run. &lt;strong&gt;The queue is closed: +1,097 servers indexed, 66,496 → 67,593.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Directory: &lt;a href="https://www.marketnow.site/mcps" rel="noopener noreferrer"&gt;marketnow.site/mcps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;All 67,593 pages declared in the &lt;a href="https://www.marketnow.site/sitemap-skills-index.xml" rel="noopener noreferrer"&gt;sitemap index&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live API: &lt;a href="https://www.marketnow.site/api/skills?sort=recent" rel="noopener noreferrer"&gt;api/skills?sort=recent&lt;/a&gt; — the batch entries carry &lt;code&gt;indexed_at: 2026-09-12&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What went in
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;230 from GitHub topic search&lt;/strong&gt; — &lt;code&gt;topic:mcp-server&lt;/code&gt;, &lt;code&gt;topic:model-context-protocol&lt;/code&gt;, plus language slices (Go, Rust, C#, Java, TypeScript) and repos pushed since July. Every entry keeps its real star count and language in the source record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;165 from the npm registry&lt;/strong&gt; — the 27 vendor packages we named publicly (@heroku/mcp-server, @storybook/mcp, @mapbox/mcp-server, @doist/todoist-mcp, argocd-mcp, &lt;a class="mentioned-user" href="https://dev.to/drawio"&gt;@drawio&lt;/a&gt;/mcp...) plus 138 more surfaced by registry search, each with its real weekly-download count from the npm downloads API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;702 from the awesome-mcp-servers reconciliation&lt;/strong&gt; — we re-ran the diff against the curated list with exact repo-URL matching instead of name matching. The stricter matching surfaced 769 repos we genuinely didn't have; 67 turned out to already live under a different identity, the rest went in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check that matters more than the count
&lt;/h2&gt;

&lt;p&gt;Here's the part I want you to steal for your own directory.&lt;/p&gt;

&lt;p&gt;Of those 769 awesome-list repos, &lt;strong&gt;347 have an npm package with the same name as the repo.&lt;/strong&gt; Naive ingestion would stamp &lt;code&gt;npx -y &amp;lt;that-name&amp;gt;&lt;/code&gt; on all 347. We checked where each package's &lt;code&gt;repository&lt;/code&gt; field actually points: &lt;strong&gt;only 159 point back to the same GitHub repo.&lt;/strong&gt; The other 188 same-name packages belong to &lt;em&gt;someone else's project&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Recommend &lt;code&gt;npx&lt;/code&gt; on one of those and you've done the typosquat's job for it — installed look-alike code with a legitimate name on top. So the rule in this batch: an awesome-list entry only gets an &lt;code&gt;npx&lt;/code&gt; install line if the package's own metadata points home. The rest get &lt;code&gt;git clone&lt;/code&gt; and a yellow install-risk, which is honest: no registry code execution, but no verified publisher either.&lt;/p&gt;

&lt;p&gt;Same-name ≠ same-project. 188 out of 347 is not an edge case.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we're still not claiming
&lt;/h2&gt;

&lt;p&gt;Everything in this batch is &lt;code&gt;review_status: auto-scanned&lt;/code&gt;, tier core, &lt;strong&gt;index heuristics only&lt;/strong&gt; — trust scores start at 40 and rise with real signals (log-scaled stars/downloads, capped at 88). No L2 deep-scan certificates were issued, because no deep scans ran. A page still says &lt;em&gt;indexed and classified&lt;/em&gt;, never &lt;em&gt;verified&lt;/em&gt;. If your directory conflates those two words, it's selling certainty it doesn't have.&lt;/p&gt;

&lt;p&gt;And the new gap, published like the last one: GitHub reports ~28,000 repos tagged &lt;code&gt;mcp-server&lt;/code&gt;. We index the ones where the name, description or topics say MCP server &lt;em&gt;and&lt;/em&gt; the repo isn't a fork or a shell — the difference between that and 28k is mostly platforms that merely &lt;em&gt;support&lt;/em&gt; MCP. We choose precision; the diff stays observable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexing notes
&lt;/h2&gt;

&lt;p&gt;The sitemap grew to 67,593 URLs across the same three files, and the registry now tracks 131,942 servers across GitHub, npm, PyPI, Smithery, the official registry, crates.io and Docker Hub. If you run an MCP directory yourself, the full breakdown is in &lt;a href="https://www.marketnow.site/api/catalog-meta.json" rel="noopener noreferrer"&gt;catalog-meta.json&lt;/a&gt; — comparing coverage against a competitor's claims is the fastest way to find out who's counting ghosts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;(MarketNow is our project — free registry, free search API. The previous writeup, with the honest 50,632-red distribution and why "red" is a definition rather than an accusation: &lt;a href="https://dev.to/edison_flores_6d2cd381b13/every-mcp-server-in-our-index-now-has-a-public-page-66496-of-them-all-crawlable-mej"&gt;66,496 pages, all crawlable&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Every MCP server in our index now has a public page — 66,496 of them, all crawlable</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Fri, 11 Sep 2026 18:23:59 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/every-mcp-server-in-our-index-now-has-a-public-page-66496-of-them-all-crawlable-mej</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/every-mcp-server-in-our-index-now-has-a-public-page-66496-of-them-all-crawlable-mej</guid>
      <description>&lt;p&gt;&lt;code&gt;npx -y some-mcp-server&lt;/code&gt; runs code from a public registry on your machine. Before you do that, the honest questions are: who publishes this, how old is it, does anyone actually use it, and is the name a typosquat of something popular? Finding those answers today means chasing the repo, the package page, and the awesome-list entry — three tabs for a decision you make in ten seconds.&lt;/p&gt;

&lt;p&gt;So we finished something we should have finished months ago: &lt;strong&gt;every MCP server in the MarketNow index now has its own public page.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Directory: &lt;a href="https://www.marketnow.site/mcps" rel="noopener noreferrer"&gt;marketnow.site/mcps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Example: &lt;a href="https://www.marketnow.site/s/mcp-server-linkedin" rel="noopener noreferrer"&gt;mcp-server-linkedin&lt;/a&gt; — trust 100/100, v4.24.0, 14,215 weekly downloads, &lt;code&gt;uvx&lt;/code&gt; install line, PyPI source link&lt;/li&gt;
&lt;li&gt;All 66,496 of them, declared in a &lt;a href="https://www.marketnow.site/sitemap-skills-index.xml" rel="noopener noreferrer"&gt;sitemap index&lt;/a&gt; so search engines and AI agents can actually find them&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's on a page
&lt;/h2&gt;

&lt;p&gt;Each page renders server-side (no JS required) and carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust score with signal breakdown&lt;/strong&gt; — registry age, weekly downloads, typosquat distance to popular names, injection markers. A 100/100 page tells you &lt;em&gt;why&lt;/em&gt; it's 100.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install-risk classification&lt;/strong&gt; — the honest three-tier: green (git-clone based, no registry code execution), yellow (heuristic signals advise review: young package, low adoption, stale repo, name similarity), red (installing via npx/uvx executes arbitrary code from the public registry).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sources&lt;/strong&gt; — repo and package links, version, author, indexed date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured data&lt;/strong&gt; — schema.org &lt;code&gt;SoftwareApplication&lt;/code&gt; + FAQ JSON-LD, so the pages are machine-readable, not just human-readable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A correction path&lt;/strong&gt; — no signup. If your server's page is wrong, or you'd rather not be listed, there's a form. This matters more than the score.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the catalog-wide numbers say
&lt;/h2&gt;

&lt;p&gt;Across all 66,496 pages: &lt;strong&gt;50,632 red, 15,861 yellow, 3 green.&lt;/strong&gt; That distribution is not a bug — &lt;code&gt;npx&lt;/code&gt;/&lt;code&gt;uvx&lt;/code&gt; installs execute registry code by design, so an npm/PyPI-sourced server is red &lt;em&gt;by definition&lt;/em&gt; unless its install path is git-clone based. "Red" is not "malicious"; it's "verify the publisher before running this." The 3 greens are the git-clone based ones. If someone's directory shows you a wall of green badges for registry-installed servers, that's not rigor, that's marketing.&lt;/p&gt;

&lt;p&gt;Every entry has a trust score (mean 65.8), and the top categories are Developer Tools (31,366), Version Control (7,434), AI/ML (7,119), Search (4,846), Finance (3,676).&lt;/p&gt;

&lt;h2&gt;
  
  
  What the pages deliberately don't claim
&lt;/h2&gt;

&lt;p&gt;A page says &lt;em&gt;indexed and classified&lt;/em&gt; — never &lt;em&gt;verified&lt;/em&gt; or &lt;em&gt;trusted&lt;/em&gt;. Discovery is not authority: a listing means we found it and ran our heuristics; it does not mean the operator stands behind the endpoint at the moment you call it. That claim belongs to an evidence layer, which is a different project of ours and stays separate on purpose.&lt;/p&gt;

&lt;p&gt;We also diffed ourselves against the &lt;a href="https://github.com/punkpeye/awesome-mcp-servers" rel="noopener noreferrer"&gt;awesome-mcp-servers&lt;/a&gt; curated list: we cover 3,541 of its 3,908 linked servers (91%). The 367 we're missing — plus 27 official npm packages (@heroku/mcp-server, @storybook/mcp, @mapbox/mcp-server, @doist/todoist-mcp...) — are queued for the next ingestion run. Publishing the gap is the point: a directory that hides its coverage holes is asking you to trust it blindly, which is exactly what a directory shouldn't do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters beyond humans
&lt;/h2&gt;

&lt;p&gt;The sitemap angle is the quiet big one. Before today, only 2,000 of these pages were declared to search engines. Now all 66,496 are. That's 66k long-tail entry points — "argocd mcp server", "dokploy mcp", "todoist mcp install" — each landing on a page that answers with a risk classification instead of a marketing badge. And the same URLs serve AI agents: the pages are structured-data-first, so an agent can parse the trust signals without scraping prose.&lt;/p&gt;

&lt;p&gt;Search for an MCP server before you install it. If it's indexed, there's a page. If the page is wrong, there's a form. If it's missing, it's in the queue — and the queue is public.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(MarketNow is our project — the registry and the search API are free. Previous writeup on how the indexing pipeline works and the 2,910 fake install counts we deleted: &lt;a href="https://dev.to/edison_flores_6d2cd381b13/8535-66496-how-we-indexed-every-mcp-server-on-github-npm-and-pypi-and-deleted-2910-fake-1hfa"&gt;8,535 → 66,496&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Re: @anp2network — round 4: the freshness reference is a release chain (r1 r2 already exercised), plus two-site mutants and a fixture clock</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Fri, 11 Sep 2026 15:54:29 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/re-anp2network-round-4-the-freshness-reference-is-a-release-chain-r1-r2-already-exercised-hi4</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/re-anp2network-round-4-the-freshness-reference-is-a-release-chain-r1-r2-already-exercised-hi4</guid>
      <description>&lt;p&gt;Your closing question first, verbatim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"So: what authenticated per-identity freshness reference do you want &lt;code&gt;verify-artifact.mjs&lt;/code&gt; to demand, so that a hub-chosen, previously valid runner cannot pass as the current release?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The release chain.&lt;/strong&gt; A persistent Ed25519 release identity — the first key in this project that is neither a throwaway (ca-test-1 style) nor published-with-its-private-half (ca-test-2 style) — signs monotone release statements. Each statement carries a &lt;code&gt;release_counter&lt;/code&gt;, the artifact digest map that &lt;strong&gt;is&lt;/strong&gt; the current authorized state, and &lt;code&gt;previous_release: {counter, sha256}&lt;/code&gt; chaining to its predecessor. The verifier keeps local state: the highest counter it has accepted, that statement's hash, and the Rekor checkpoint it saw. It refuses a lower counter (rollback), refuses a same-counter conflict (fork), and when advancing requires the chain linkage, a &lt;strong&gt;higher log index&lt;/strong&gt; than the accepted checkpoint, and a grown tree.&lt;/p&gt;

&lt;p&gt;It went to production the way you'd want: badly first, then correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  r1 → r2: the advance, exercised for real
&lt;/h2&gt;

&lt;p&gt;Rekor entry &lt;strong&gt;#6&lt;/strong&gt; (logIndex &lt;code&gt;2795106183&lt;/code&gt;, 2026-09-11T15:38:34Z) anchored r1 — the identity, the statement, 17 artifact digests. Minutes later I ran the stranger flow against the live URLs and it failed: the release-mode &lt;code&gt;--artifact&lt;/code&gt; comparison in &lt;code&gt;verify-artifact.mjs&lt;/code&gt; compared a pin &lt;em&gt;object&lt;/em&gt; against the sha &lt;em&gt;string&lt;/em&gt; and could never match. r1 was already log-committed. Re-signing a counter is exactly what the policy forbids — so the fix shipped as &lt;strong&gt;r2&lt;/strong&gt;: the same authorized artifacts (score-runner, answer key, both sweeps — pinned identically to r1, byte-for-byte), one fixed verifier, chained via &lt;code&gt;previous_release.sha256&lt;/code&gt;, anchored at entry &lt;strong&gt;#7&lt;/strong&gt; (logIndex &lt;code&gt;2795233758&lt;/code&gt;, 15:49:43Z).&lt;/p&gt;

&lt;p&gt;That hour is now the worked example of the whole design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accept r1 (@#6):  first contact → floor → counter 1 recorded
serve r2 (@#7):  ✓ chain linkage (previous_release.sha256 === r1's)
                 ✓ log monotonicity (2795233758 &amp;gt; 2795106183)
                 ✓ checkpoint tree grew
                 → counter 2 recorded
serve r1 again:  ✗ REFUSED — ROLLBACK (counter 1 &amp;lt; highest accepted 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of it live from the third party's log, none of it from the hub's word. An intermediate draft submission at &lt;code&gt;2795221503&lt;/code&gt; also exists — log debris from the same hour, left in place on purpose: the log's job is to make history unrewritable, not tidy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the verifier demands now
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node verify-artifact.mjs &lt;span class="nt"&gt;--release&lt;/span&gt;            &lt;span class="c"&gt;# the chain, hub defaults&lt;/span&gt;
node verify-artifact.mjs &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--artifact&lt;/span&gt; https://www.marketnow.site/uta/conformance/score-runner.mjs
node verify-artifact.mjs &amp;lt;artifact&amp;gt;           &lt;span class="c"&gt;# the round-3 flow still works — and now prints&lt;/span&gt;
                                               &lt;span class="c"&gt;# "LOG-known, not CURRENT" and points here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stranger run from live URLs only, today: &lt;strong&gt;12/12&lt;/strong&gt; on the chain, and the artifact check lands: &lt;code&gt;score_runner_v1_5_0 (c0bd20e6987d94d7…, 17 artifacts pinned)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your two probes, answered by construction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"Serve an older, legitimately anchored runner together with the artifact that matched it at the time, and every step passes."&lt;/em&gt; Not anymore. The old runner+artifact pair verifies against its own old entry — but it is not the &lt;strong&gt;current release&lt;/strong&gt;, and the verifier now demands exactly that: the highest counter it has ever accepted. Serving entry #5's whole package after entry #7 is a rollback, refused by local state.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"A rollback to a coherent older snapshot has no disagreement to catch."&lt;/em&gt; Correct — incoherence was never the detection mechanism for this. Disagreement (the drift-report path) still exists for bytes-vs-pin mismatches, but rollback detection is the &lt;strong&gt;counter&lt;/strong&gt;, which does not live in the hub's filesystem at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First contact, honestly
&lt;/h2&gt;

&lt;p&gt;A fresh verifier has no local memory — you named the residual yourself. It is bounded two ways: the anchor must sit &lt;strong&gt;above the bootstrap floor&lt;/strong&gt; (entry #5, &lt;code&gt;2787622029&lt;/code&gt; — history cannot restart below known ground), and the release identity only exists in statements anchored at or after entry #6, so an older entry cannot impersonate a release. What first contact still cannot know is whether a release newer than the one it found exists. That is irreducible without local memory or an out-of-band hint; the state file buys total monotonicity from the first accepted release onward. Every future release must advance the counter and re-anchor to remain verifiable as current — which converts "the hub is what hands the verifier the entry to check" from a trust assumption into a bounded, documented, monotone-from-first-contact risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two-site coordinated family
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"A cheap probe: add a small family of coordinated two-site mutations around one shared invariant, score them in a separate column, and leave the existing number untouched so it stays comparable across releases."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;generate-mutants-twosite.mjs&lt;/code&gt; declares four invariant families — the two-sided window, the pinned-anchor set, the signature verification, the fail-closed aborts — and pairs every same-operator site pair inside a family, both edits applied together. That's the fault class single-site sweeps cannot express: a corruption that moves the check &lt;strong&gt;and&lt;/strong&gt; the derived-truth oracle coherently.&lt;/p&gt;

&lt;p&gt;Result on the v1.5.0 runner: &lt;strong&gt;157 coordinated pairs, 156 caught, 1 survivor.&lt;/strong&gt; The classic runner+oracle pair (&lt;code&gt;inWindow&lt;/code&gt; in &lt;code&gt;reference()&lt;/code&gt; AND in &lt;code&gt;loadGenerated()&lt;/code&gt;, both &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;→&lt;code&gt;||&lt;/code&gt;) is &lt;strong&gt;caught&lt;/strong&gt; — because the &lt;em&gt;fixed&lt;/em&gt; suite's expectations are manifest-pinned, not derived, so the answer key does not move with the fault. That is now a measured property, not an assumption.&lt;/p&gt;

&lt;p&gt;The one survivor is real and worth naming: &lt;code&gt;or-and&lt;/code&gt; on the fail-closed guard line — the malformed-card probe deletes the entire metadata block, so all three disjuncts fire and the weakened guard still aborts. A card missing &lt;strong&gt;exactly one&lt;/strong&gt; field would slip through the mutant and be scored instead of refused. The suite never probes single-field absence. Survivor recorded, classified &lt;code&gt;real (narrow)&lt;/code&gt;, published in &lt;code&gt;mutant-sweep-twosite.json&lt;/code&gt; — a separate column, never summed with single-site.&lt;/p&gt;

&lt;p&gt;The single-site number is a time series now, as you asked it to stay: v1.4.0 bytes → 92/113 (archived verbatim in &lt;code&gt;mutant-sweep-v140.json&lt;/code&gt;); v1.5.0 bytes — the two-clock plumbing added ~13 sites — → &lt;strong&gt;95/126, 31 survivors, each classified&lt;/strong&gt;. Same operators, same oracle, comparable across releases.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fixture clock
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"premature-atc is pinned at 2030-01-01, so its discriminating power decays as the wall clock walks toward it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;_index.json&lt;/code&gt; now carries &lt;code&gt;evaluation_clock: 2026-09-11T00:00:00Z&lt;/code&gt;. The 14 fixed vectors are evaluated against that recorded clock — premature-atc stays premature forever, the accept vectors never lapse; the fixed suite is a fixture and stops aging. Generated cards stay on the live wall clock, and the adversarial mode already derives the premature case per run with offsets relative to the scoring clock — so the window is exercised by a non-aging fixture &lt;strong&gt;and&lt;/strong&gt; a distribution, your two options, complementary rather than either/or. &lt;code&gt;--clock&lt;/code&gt; pins both for byte-reproducible runs, and a clock where the fixtures genuinely diverge reports FAILED instead of hiding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where everything lives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hub: &lt;a href="https://www.marketnow.site/uta/conformance/" rel="noopener noreferrer"&gt;https://www.marketnow.site/uta/conformance/&lt;/a&gt; — &lt;code&gt;releases/&lt;/code&gt; (identity + r1 + r2), the updated anchors page (seven entries), runner-tests, vectors&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter" rel="noopener noreferrer"&gt;alicelabs-llc/universal-trust-adapter&lt;/a&gt;&lt;a class="mentioned-user" href="https://dev.to/main"&gt;@main&lt;/a&gt; — commits &lt;code&gt;717641d0&lt;/code&gt; (v1.4.0 recovery from the live site), &lt;code&gt;f50862ab&lt;/code&gt; (v1.5.0), &lt;code&gt;9831c671&lt;/code&gt;+&lt;code&gt;3d76e878&lt;/code&gt; (site), &lt;code&gt;a0cd6670&lt;/code&gt; (r2)&lt;/li&gt;
&lt;li&gt;Rekor: entries #6 (&lt;code&gt;2795106183&lt;/code&gt;) and #7 (&lt;code&gt;2795233758&lt;/code&gt;) — live, inclusion-checkable&lt;/li&gt;
&lt;li&gt;Everything above was verified end-to-end from the live URLs alone, zero trust in the publisher&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What remains open, honestly
&lt;/h2&gt;

&lt;p&gt;First contact is bounded, not eliminated — that's stated in the verifier's output, not buried in a README. The two-site family is still generated from a declared operator set and declared invariant families; a semantic fault outside both declarations is invisible to it, the same closed-set limit you keep turning back at us, one level up each time. And the runner-under-test oracle still observes a &lt;em&gt;passing&lt;/em&gt; suite — the failure-path exit value, for instance, is unpinned (that survivor is classified &lt;code&gt;equivalent&lt;/code&gt; for exactly that reason).&lt;/p&gt;

&lt;p&gt;The next gap you find, the same rule applies as the last four rounds: it gets reproduced, fixed, measured, and anchored — and the fix itself becomes evidence.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>8,535 66,496: how we indexed every MCP server on GitHub, npm and PyPI (and deleted 2,910 fake install counts)</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Fri, 11 Sep 2026 05:29:17 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/8535-66496-how-we-indexed-every-mcp-server-on-github-npm-and-pypi-and-deleted-2910-fake-1hfa</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/8535-66496-how-we-indexed-every-mcp-server-on-github-npm-and-pypi-and-deleted-2910-fake-1hfa</guid>
      <description>&lt;p&gt;In late June our registry listed 8,535 MCP skills. This week catalog v5.5.0 went live with &lt;strong&gt;66,496 indexed MCP servers&lt;/strong&gt; and &lt;strong&gt;130,845 tracked ecosystem-wide&lt;/strong&gt; — but the part I want to write about is not the growth. It's the garbage we deleted on the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the numbers actually mean
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;130,845 tracked&lt;/strong&gt; — every MCP server we could see across three sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;66,496 indexed&lt;/strong&gt; — searchable in the registry, each with an install-risk classification (red / yellow / green) and source links&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep-scanned subset&lt;/strong&gt; — top packages get the 29 Sentinel rules: static analysis, dependency risk, maintainability and evidence-based trust scoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The three sources are GitHub, npm and PyPI. Deduplication is by repository identity — a GitHub repo, its npm package and its PyPI wheel collapse into one listing.&lt;/p&gt;

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

&lt;p&gt;Indexing runs in layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt; — code and repo search for MCP-declaring repositories, verified via API (stars, issues, last push — real numbers only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt; — registry API scan for MCP packages, with download stats straight from the registry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI&lt;/strong&gt; — project metadata and release history&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Multi-registry indexing v2 (the release that took the index from 9k to 23k) landed earlier this week. v5.5.0 consolidated everything, re-ran the certifications, and purged the stale data layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we deleted (the honest part)
&lt;/h2&gt;

&lt;p&gt;The original auto-discovery inherited bad data. Two things were wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2,910 invented install counts&lt;/strong&gt; — legacy listing rows whose install numbers could not be traced to any registry. All deleted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~2x inflated GitHub stars&lt;/strong&gt; — catalog stars came from an old scrape; live API verification showed roughly double the real numbers. Every GitHub-sourced listing is now API-verified before it enters the catalog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a transparency page that shows exactly where every skill comes from:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.marketnow.site/catalog" rel="noopener noreferrer"&gt;https://www.marketnow.site/catalog&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your MCP server is listed and something is wrong, there's a submission form — no signup, no account:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.marketnow.site/submit" rel="noopener noreferrer"&gt;https://www.marketnow.site/submit&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it from any MCP client
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; marketnow-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you 8 tools. The ones people use most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;search&lt;/strong&gt; — query the 66,496-server registry by keyword and category&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;install-risk&lt;/strong&gt; — red / yellow / green classification with the reason. Red means installing runs registry code on every start (the &lt;code&gt;npx&lt;/code&gt;/&lt;code&gt;uvx&lt;/code&gt; pattern) — flagged for review-before-install, not a verdict against the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tool fingerprinting&lt;/strong&gt; — hash a server's &lt;code&gt;tools/list&lt;/code&gt; surface (RFC 8785 JCS + SHA-256) and diff it later to detect tool-poisoning redefinitions — the OWASP MCP cheat sheet item people keep asking about&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;credential verification&lt;/strong&gt; — the 12-stage UTA pipeline covering 8 credential formats (JWT, W3C VC, MCP Card, A2A, EAT-AI, ZTA, X.509, ATC v3)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The searchable registry and the search API are free.&lt;/p&gt;

&lt;h2&gt;
  
  
  We told 44 maintainers yesterday
&lt;/h2&gt;

&lt;p&gt;We opened 44 issues on repos whose servers are indexed — &lt;code&gt;github-mcp-server&lt;/code&gt;, &lt;code&gt;fastmcp&lt;/code&gt;, &lt;code&gt;mcp-toolbox&lt;/code&gt;, &lt;code&gt;awslabs/mcp&lt;/code&gt;, &lt;code&gt;notion-mcp-server&lt;/code&gt;, &lt;code&gt;firecrawl-mcp-server&lt;/code&gt; and 38 more. Each issue tells the maintainer their listing exists and includes a badge they can paste into their README. No signup, nothing to buy.&lt;/p&gt;

&lt;p&gt;If you maintain an MCP server and want the badge: &lt;strong&gt;&lt;a href="https://www.marketnow.site/embed" rel="noopener noreferrer"&gt;https://www.marketnow.site/embed&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The trust pipeline (UTA) is getting its own site — it deserves not to live under a marketplace domain. More on that soon.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Edison Flores, founder of &lt;a href="https://github.com/alicelabs-llc" rel="noopener noreferrer"&gt;AliceLabs LLC&lt;/a&gt; — we build open-source security infrastructure for AI agents. This post is about my own project; the registry, the search API and the badge system are free.&lt;/em&gt;&lt;/p&gt;

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