<?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: Kioi</title>
    <description>The latest articles on DEV Community by Kioi (@kioiek).</description>
    <link>https://dev.to/kioiek</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%2F3959026%2F5155e329-e4e4-4886-92f6-ca50e7ba87fe.jpg</url>
      <title>DEV Community: Kioi</title>
      <link>https://dev.to/kioiek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kioiek"/>
    <language>en</language>
    <item>
      <title>Of Malicious MCP servers!</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Thu, 09 Jul 2026 03:43:40 +0000</pubDate>
      <link>https://dev.to/kioiek/of-malicious-mcp-servers-35ga</link>
      <guid>https://dev.to/kioiek/of-malicious-mcp-servers-35ga</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kioiek/the-first-malicious-mcp-server-and-what-it-taught-us-about-trust-h0m" class="crayons-story__hidden-navigation-link"&gt;The First Malicious MCP Server and What It Taught Us About Trust&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kioiek" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3959026%2F5155e329-e4e4-4886-92f6-ca50e7ba87fe.jpg" alt="kioiek profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kioiek" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kioi
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kioi
                
              
              &lt;div id="story-author-preview-content-4074810" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kioiek" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3959026%2F5155e329-e4e4-4886-92f6-ca50e7ba87fe.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kioi&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kioiek/the-first-malicious-mcp-server-and-what-it-taught-us-about-trust-h0m" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 5&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kioiek/the-first-malicious-mcp-server-and-what-it-taught-us-about-trust-h0m" id="article-link-4074810"&gt;
          The First Malicious MCP Server and What It Taught Us About Trust
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/api"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;api&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/agents"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;agents&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/kioiek/the-first-malicious-mcp-server-and-what-it-taught-us-about-trust-h0m#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>The First Malicious MCP Server and What It Taught Us About Trust</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Sun, 05 Jul 2026 20:09:11 +0000</pubDate>
      <link>https://dev.to/kioiek/the-first-malicious-mcp-server-and-what-it-taught-us-about-trust-h0m</link>
      <guid>https://dev.to/kioiek/the-first-malicious-mcp-server-and-what-it-taught-us-about-trust-h0m</guid>
      <description>&lt;p&gt;In September 2025, a security team at Koi discovered something that, in hindsight, was inevitable. A package on npm called &lt;code&gt;postmark-mcp&lt;/code&gt; a Model Context Protocol server that let AI assistants send email through Postmark, had been quietly turned into a weapon. The story is almost boringly simple, and that is exactly what makes it worth studying.&lt;/p&gt;

&lt;p&gt;An engineer copied Postmark’s legitimate open-source MCP server, near line for line, and published it under his own name. The first fifteen versions were clean. They did precisely what they claimed. People installed them, wired them into their agents, and moved on. Then version 1.0.16 shipped. It was identical to the version before it, except for a single line, line 231, that added a blind carbon copy to &lt;code&gt;phan@giftshop[.]club&lt;/code&gt; on every outgoing message. From that point on, every email an AI assistant sent through the tool, password resets, invoices, credentials, contracts, was silently forwarded to a stranger. The package was downloaded 1,643 times before anyone noticed.&lt;/p&gt;

&lt;p&gt;We keep coming back to this incident when we reason about the problem we work on, because it strips away everything incidental and leaves the core issue exposed. So let us walk through the reasoning the way we actually walked through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust was placed once, and never checked again
&lt;/h2&gt;

&lt;p&gt;Start with the obvious question: at what moment did the people using &lt;code&gt;postmark-mcp&lt;/code&gt; get compromised? It is tempting to say "&lt;em&gt;when they installed 1.0.16.&lt;/em&gt;" But that is not quite right. They were compromised the moment they decided, at install time, that this tool was safe and then never revisited that decision.&lt;/p&gt;

&lt;p&gt;This is the pattern we kept seeing, across incident after incident. Trust is a point-in-time act. You inspect a schema, review a tool, approve a permission, and form a judgment: &lt;em&gt;this is the shape of the thing I am depending on&lt;/em&gt;. And then you build on top of that judgment as if it were permanent. But the thing you depended on is not permanent. It is a living artifact that someone else controls, and it can change underneath you at any time, for any reason, with no obligation to tell you.&lt;/p&gt;

&lt;p&gt;The first fifteen versions being clean was not reassuring. It was the attack. Fifteen honest versions is precisely how you earn the trust that the sixteenth version spends. The whole exploit lives in the gap between “I evaluated this once” and “this is still what I evaluated.”&lt;/p&gt;

&lt;p&gt;So the first idea we arrived at is almost embarrassingly plain: &lt;em&gt;the shape of a dependency is not a fact you establish once.&lt;/em&gt; It is a value you have to keep measuring. If trust decays the instant a contract can change, then the only honest thing to do is to treat the contract as something you re-check continuously, not something you approve and forget.&lt;/p&gt;

&lt;p&gt;To watch for change, you first have to make the contract a thing you can hold&lt;/p&gt;

&lt;p&gt;The next question follows naturally. If we want to notice when a tool or a schema changes, what exactly are we comparing?&lt;/p&gt;

&lt;p&gt;You cannot diff a vibe. “&lt;em&gt;This tool felt trustworthy&lt;/em&gt;” is not comparable across time. What is comparable is the concrete, structural description of the thing: the fields in a payload and their types, the tools an MCP server advertises, the parameters each tool accepts, the description text the model reads to decide how to use it. These are the promises, and crucially, they can be captured as explicit artifacts snapshots you can store, version, and set side by side.&lt;br&gt;
Write on Medium&lt;/p&gt;

&lt;p&gt;This led us to the second idea: &lt;em&gt;before you can guard a contract, you have to render it into something inspectable and stable.&lt;/em&gt; Turn the live, shifting surface of an API or a tool catalog into a captured shape. Once you have that, the impossible question, “&lt;em&gt;did I get compromised?&lt;/em&gt;” becomes a mechanical one: &lt;em&gt;is today’s shape the same as the shape I approved?&lt;/em&gt; The &lt;code&gt;postmark-mcp&lt;/code&gt; attack, viewed this way, is not subtle at all. Version 1.0.15 and version 1.0.16 describe the same tools, but their behavior diverged. Even the visible metadata — versions, hashes, tool listings — moved. A system holding yesterday's snapshot next to today's would have had something concrete to point at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not all change is attack — so the comparison has to have judgment
&lt;/h2&gt;

&lt;p&gt;Here we hit the complication that makes this a real engineering problem and not just a checksum. Contracts &lt;strong&gt;should&lt;/strong&gt; change. APIs add fields. Tools improve their descriptions. If every difference screams, you have built an alarm that everyone learns to ignore, and an ignored alarm is worse than none.&lt;/p&gt;

&lt;p&gt;So the third idea: &lt;em&gt;a useful comparison distinguishes the change that breaks a promise from the change that merely extends it.&lt;/em&gt; Adding an optional field is not the same as removing a required one. A new tool appearing is a different risk than an existing tool quietly growing a new parameter, or its description mutating in a way that could steer an agent toward a new, unintended action. The comparison has to classify safe versus breaking, additive versus destructive, so that human attention is spent only where a promise actually broke. This is what turns raw diffing into something you can put in front of a team without exhausting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cheapest place to catch drift is before it ships, but that’s not the only place
&lt;/h2&gt;

&lt;p&gt;Now, &lt;strong&gt;where&lt;/strong&gt; do you run this check? Reasoning it through, there are two distinct moments, and you need both.&lt;/p&gt;

&lt;p&gt;The first is at the boundary of your own changes, before code merges. When your integration assumes a certain response shape, the moment to discover the assumption is wrong is at the pull request, not at 2am in production. Catching drift here is the cheap catch: it is a gate you put in the path of change, and it fails the build before the bad assumption ever reaches a user. This is drift you cause, and you can stop it upstream.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;postmark-mcp&lt;/code&gt; is the other kind entirely. Nobody on the victim side changed anything. Their code was stable. The drift came from outside, on someone else's release schedule, long after their last merge. No pre-merge gate on earth would have caught it, because there was no merge. This is the fourth idea, and it is the one most tooling misses: some of the most dangerous drift happens in things you depend on but do not control, and it happens continuously, on a clock you don't own. Catching it requires something that keeps polling the live surface, re-fetching the tool catalog, re-reading the advertised shapes, on its own schedule, forever, and raising a hand the moment the shape you approved is no longer the shape being served.&lt;/p&gt;

&lt;h2&gt;
  
  
  And when it changes, someone has to be told, with the receipt
&lt;/h2&gt;

&lt;p&gt;The final piece is almost anticlimactic but it is where most good intentions die. A check that runs and notices a change is useless if the noticing lands in a log nobody reads. The value is only realized at the moment a human is interrupted with a specific, legible claim: &lt;em&gt;this tool’s contract changed at this time, in this way, and here is the before and the after.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is the fifth idea: detection is only half of it; the other half is delivery and history. You need the alert that reaches a person, and you need the durable record, the timeline of a contract’s shape over weeks, so that when something does go wrong, you can answer the question the &lt;code&gt;postmark-mcp&lt;/code&gt; victims could not answer for days: &lt;em&gt;when did this change, and what were we exposed to in between?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So, to the landing
&lt;/h2&gt;

&lt;p&gt;Put those ideas in a line and they compose into a single discipline. Capture the contract as an explicit, comparable shape. Diff it with enough judgment to separate breaking change from benign growth. Gate your own changes before they merge. Poll the surfaces you depend on but do not control, continuously, because their drift is not on your schedule. And when a promise breaks, tell a human, with the full receipt.&lt;/p&gt;

&lt;p&gt;We wanted to test this ideas out and built them into &lt;a href="https://driftguard.org/" rel="noopener noreferrer"&gt;DriftGuard&lt;/a&gt;. The local diff that classifies breaking changes and fits into CI is the cheap, upstream catch. The continuous watches that poll live API and MCP tool catalogs are for the drift you don’t control. The &lt;code&gt;postmark-mcp-shaped&lt;/code&gt; drift that no pre-merge test can see. The alerting and the history are what turn a detected change into a decision someone can actually act on. None of these are clever in isolation. What makes them matter is that the threat is now continuous and external, and so the guard has to be continuous too.&lt;/p&gt;

&lt;p&gt;The lesson of the first malicious MCP server is not that MCP is dangerous. It is that we have been treating trust as a thing you establish once, in a world where the things we trust can change every day, on someone else’s terms. Closing that gap, measuring the promise continuously instead of approving it once is the work. &lt;code&gt;postmark-mcp&lt;/code&gt; is simply the clearest argument we have found for why it can't wait.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>architecture</category>
      <category>agents</category>
    </item>
    <item>
      <title>When agents loop endlessly!</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Sat, 04 Jul 2026 04:15:18 +0000</pubDate>
      <link>https://dev.to/kioiek/when-agents-loop-endlessly-l1o</link>
      <guid>https://dev.to/kioiek/when-agents-loop-endlessly-l1o</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4" class="crayons-story__hidden-navigation-link"&gt;FuseGuard: Trip Agent Loops Locally, See Blocks in Your Fleet Console&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kioiek" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3959026%2F5155e329-e4e4-4886-92f6-ca50e7ba87fe.jpg" alt="kioiek profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kioiek" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kioi
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kioi
                
              
              &lt;div id="story-author-preview-content-4041119" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kioiek" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3959026%2F5155e329-e4e4-4886-92f6-ca50e7ba87fe.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kioi&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 1&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4" id="article-link-4041119"&gt;
          FuseGuard: Trip Agent Loops Locally, See Blocks in Your Fleet Console
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              2&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>FuseGuard: Trip Agent Loops Locally, See Blocks in Your Fleet Console</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Wed, 01 Jul 2026 11:51:37 +0000</pubDate>
      <link>https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4</link>
      <guid>https://dev.to/kioiek/fuseguard-trip-agent-loops-locally-see-blocks-in-your-fleet-console-14e4</guid>
      <description>&lt;p&gt;Agents retry forever when a tool schema drifts or a loop never terminates.&lt;/p&gt;

&lt;p&gt;Your service dashboards look fine. Stripe still charges. Meanwhile the model burns tokens on &lt;code&gt;tools/call&lt;/code&gt; that will never succeed — or spins in a loop because nothing enforces a fuse at the edge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FuseGuard&lt;/strong&gt; is the runtime complement to contract watches: DriftGuard tells you when a vendor &lt;strong&gt;changed&lt;/strong&gt; the schema; FuseGuard &lt;strong&gt;stops&lt;/strong&gt; bad calls before they compound. This post walks OSS policy simulation, then the hosted fleet console — about 10 minutes if you follow along.&lt;/p&gt;




&lt;h2&gt;
  
  
  The gap HTTP monitoring misses
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Sees runaway agent spend?&lt;/th&gt;
&lt;th&gt;Sees MCP catalog drift?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API latency / 5xx&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduled &lt;code&gt;tools/list&lt;/code&gt; diff&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (DriftGuard watches)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local policy fuse on tool invocation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When wired to drift signals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You want both: &lt;strong&gt;observe&lt;/strong&gt; contracts on a schedule, &lt;strong&gt;trip&lt;/strong&gt; fuses at invocation time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — OSS fuse in CI (no card)
&lt;/h2&gt;

&lt;p&gt;Install the open-source FuseGuard CLI from the DriftGuard repo and simulate a loop before merge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Drift-Guard/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard/packages/fuseguard  &lt;span class="c"&gt;# or follow README install path&lt;/span&gt;
fuseguard doctor
fuseguard policy simulate &lt;span class="nt"&gt;--policy&lt;/span&gt; examples/fuseguard/fuse.policy.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tool&lt;/span&gt; loop_tool &lt;span class="nt"&gt;--iteration&lt;/span&gt; 12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Policy denies the loop before another model round — same class of protection teams wire in agent gateways.&lt;/p&gt;

&lt;p&gt;Wire &lt;code&gt;fuseguard policy lint&lt;/code&gt; on PRs that touch agent tool manifests or MCP config. Fail fast when a change removes fuse rules your production overlay expects.&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://driftguard.org/features/fuseguard" rel="noopener noreferrer"&gt;FuseGuard on driftguard.org&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Hosted fleet console (demo)
&lt;/h2&gt;

&lt;p&gt;Open the &lt;strong&gt;Fuse&lt;/strong&gt; view in the demo console (no signup required for the tour):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://driftguard.org/console?demo=1&amp;amp;view=fuse&amp;amp;utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-fuseguard-fleet" rel="noopener noreferrer"&gt;driftguard.org/console?demo=1&amp;amp;view=fuse&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What to look for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Activity&lt;/strong&gt; — block reasons such as &lt;code&gt;loop_detected&lt;/code&gt; and &lt;code&gt;contract_drift_blocked&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt; — estimated USD saved from denied invocations (FinOps-oriented, not vanity charts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt; — org-level kill switch when you need to stop an agent fleet quickly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the production overlay enabled, devices sync &lt;strong&gt;trip metadata&lt;/strong&gt; to the hosted index — not full prompt exfiltration, just enough to audit blocks across a team.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Correlate drift → fuse
&lt;/h2&gt;

&lt;p&gt;When a watch classifies a &lt;strong&gt;breaking&lt;/strong&gt; change on an MCP endpoint, FuseGuard can block &lt;code&gt;tools/call&lt;/code&gt; against the stale schema instead of letting the agent retry into a bill spike.&lt;/p&gt;

&lt;p&gt;In the console, open a block row tied to a drifted watch — you get the incident trail from contract observability through runtime enforcement. That is the story we tell in sales engineering demos: &lt;strong&gt;detect on schedule, deny on invoke&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing path (practitioner voice)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Today:&lt;/strong&gt; OSS fuse + policy lint in CI — no hosted key required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When you need fleet metrics:&lt;/strong&gt; enable the FuseGuard product overlay on Pro-tier hosting; start with one endpoint on trial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://driftguard.org/start?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-fuseguard-fleet" rel="noopener noreferrer"&gt;Start free&lt;/a&gt;&lt;/strong&gt; — same trial as MCP watches; add FuseGuard from the console when you are ready.&lt;/p&gt;

&lt;p&gt;Partner practitioners who recommend tools like this: &lt;a href="https://driftguard.org/partners?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-fuseguard-fleet" rel="noopener noreferrer"&gt;driftguard.org/partners&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How this fits the DriftGuard series
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Product surface&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline + diff&lt;/td&gt;
&lt;td&gt;OSS &lt;code&gt;compare_json&lt;/code&gt;, CI gates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduled contract polls&lt;/td&gt;
&lt;td&gt;Hosted watches + alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime fuse + fleet&lt;/td&gt;
&lt;td&gt;FuseGuard OSS + console overlay&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Earlier posts in this series: &lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;silent MCP drift&lt;/a&gt;, &lt;a href="https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2"&gt;ToolSchema lab&lt;/a&gt;, &lt;a href="https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0"&gt;CI gate&lt;/a&gt;, &lt;a href="https://dev.to/kioiek/catch-mcp-tool-catalog-drift-before-your-agent-ships-broken-integrations"&gt;contract drift monitoring&lt;/a&gt; &lt;em&gt;(this queue — link updates after publish)&lt;/em&gt;.&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;fuseguard policy simulate&lt;/code&gt; on a loop fixture in your repo.&lt;/li&gt;
&lt;li&gt;Open the &lt;a href="https://driftguard.org/console?demo=1&amp;amp;view=fuse&amp;amp;utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-fuseguard-fleet" rel="noopener noreferrer"&gt;demo console Fuse view&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://driftguard.org/start?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-fuseguard-fleet" rel="noopener noreferrer"&gt;Start a trial&lt;/a&gt;&lt;/strong&gt; when you want one watched MCP endpoint plus fleet overlay.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; Where would you enforce a fuse first — CI on policy files, the agent gateway, or both? Reply with your stack (Cursor, custom gateway, etc.) — I use threads to prioritize the next tutorial.&lt;/p&gt;




&lt;h2&gt;
  
  
  Series links
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;Market gap / launch&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Why silent MCP drift happens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2"&gt;ToolSchema lab&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Hands-on MCP lab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0"&gt;CI gate&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;GitHub Actions funnel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi"&gt;MCP tool removed postmortem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Incident timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Drift-Guard/driftguard" rel="noopener noreferrer"&gt;Drift-Guard/driftguard&lt;/a&gt; · FuseGuard: &lt;a href="https://driftguard.org/features/fuseguard" rel="noopener noreferrer"&gt;driftguard.org/features/fuseguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>devops</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Catch MCP Tool Catalog Drift Before Your Agent Ships Broken Integrations</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Tue, 30 Jun 2026 11:40:22 +0000</pubDate>
      <link>https://dev.to/kioiek/catch-mcp-tool-catalog-drift-before-your-agent-ships-broken-integrations-pdf</link>
      <guid>https://dev.to/kioiek/catch-mcp-tool-catalog-drift-before-your-agent-ships-broken-integrations-pdf</guid>
      <description>&lt;p&gt;Your agent can pass every test in the repo and still ship broken on Monday.&lt;/p&gt;

&lt;p&gt;The failure mode is boring: a vendor updates an MCP server, removes a tool from &lt;code&gt;tools/list&lt;/code&gt;, or tightens &lt;code&gt;inputSchema&lt;/code&gt;. Cursor and Claude cache what they saw last week. Your HTTP monitors stay green. CI only diffs &lt;strong&gt;your&lt;/strong&gt; OpenAPI. Then &lt;code&gt;tools/call&lt;/code&gt; starts returning empty turns — and support asks why "the AI stopped filing tasks."&lt;/p&gt;

&lt;p&gt;We have covered the &lt;strong&gt;why&lt;/strong&gt; in &lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;silent MCP drift&lt;/a&gt;, a &lt;strong&gt;hands-on lab&lt;/strong&gt; in &lt;a href="https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2"&gt;ToolSchema Kit&lt;/a&gt;, and the &lt;strong&gt;CI funnel&lt;/strong&gt; in &lt;a href="https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0"&gt;MCP contract coverage gates&lt;/a&gt;. This post is the &lt;strong&gt;monitoring lane&lt;/strong&gt;: baseline external MCP contracts, classify breaking vs noise, and alert before production traffic proves the gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  What breaks (and what does not)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Catches MCP catalog drift?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Service APM / 5xx rate&lt;/td&gt;
&lt;td&gt;No — handshake can succeed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAPI lint on your API&lt;/td&gt;
&lt;td&gt;No — vendor MCP is out of repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frozen JSON fixtures in unit tests&lt;/td&gt;
&lt;td&gt;No — mocks hide live shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduled poll on &lt;code&gt;tools/list&lt;/code&gt; + diff&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sentry sees runtime stack traces. You need &lt;strong&gt;contract observability&lt;/strong&gt; on dependencies you do not own.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — Preview watches from mcp.json (offline)
&lt;/h2&gt;

&lt;p&gt;Before you register anything hosted, enumerate what your agent actually calls.&lt;/p&gt;

&lt;p&gt;DriftGuard ships a local MCP tool &lt;code&gt;parse_mcp_config&lt;/code&gt; that reads &lt;code&gt;.cursor/mcp.json&lt;/code&gt; (or your project's MCP config) and lists candidate URLs — no API key required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Drift-Guard/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm ci &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build
npm run mcp
&lt;span class="c"&gt;# In your MCP client: parse_mcp_config with your config path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use the starter block from &lt;a href="https://github.com/Drift-Guard/driftguard/blob/main/examples/mcp-client-config.json" rel="noopener noreferrer"&gt;examples/mcp-client-config.json&lt;/a&gt; in Cursor settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; a shortlist of MCP HTTP/SSE endpoints worth watching — not every line in the file, only tool surfaces that can drift.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Baseline fixtures in CI (free, local)
&lt;/h2&gt;

&lt;p&gt;Pin &lt;code&gt;tools/list&lt;/code&gt; (or OpenAPI payloads) as versioned JSON in the repo. Diff on every PR with the OSS &lt;code&gt;compare_json&lt;/code&gt; semantics — breaking field removals fail the build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/driftguard.yml (excerpt)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drift-Guard/driftguard/.github/actions/drift-diff@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fixtures/mcp-tools-list-baseline.json&lt;/span&gt;
    &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fixtures/mcp-tools-list-current.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That catches &lt;strong&gt;your&lt;/strong&gt; intentional updates. It does not catch &lt;strong&gt;vendor&lt;/strong&gt; changes on Saturday night unless you also poll live endpoints — that is step 3.&lt;/p&gt;

&lt;p&gt;Full progressive funnel (preview → trial → Pro gate): &lt;a href="https://driftguard.org/ci/setup" rel="noopener noreferrer"&gt;CI setup guide&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Hosted watch on one endpoint (trial)
&lt;/h2&gt;

&lt;p&gt;For the MCP server that actually blocks your agent workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://driftguard.org/start?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-mcp-contract-drift" rel="noopener noreferrer"&gt;Start a trial&lt;/a&gt;&lt;/strong&gt; — no card, one endpoint at full Pro depth.&lt;/li&gt;
&lt;li&gt;Register a watch on the live &lt;code&gt;tools/list&lt;/code&gt; URL or OpenAPI document.&lt;/li&gt;
&lt;li&gt;DriftGuard snapshots on schedule, classifies diffs (breaking vs informational), and routes alerts to Slack/PagerDuty when you are ready.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify your session:&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;-sS&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$DRIFTGUARD_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; https://driftguard.org/api/me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Open core boundary:&lt;/strong&gt; diff and MCP preview are local/OSS; continuous polls, history, and alert routing are hosted. Clone path until npm publish is fully wired: &lt;a href="https://github.com/Drift-Guard/driftguard" rel="noopener noreferrer"&gt;github.com/Drift-Guard/driftguard&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real incident pattern
&lt;/h2&gt;

&lt;p&gt;A team we wrote up in &lt;a href="https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi"&gt;MCP tool removed over the weekend&lt;/a&gt; went ~62 hours from vendor deploy to human discovery. Uptime was fine. After a watch on &lt;code&gt;tools/list&lt;/code&gt;, a similar change surfaced in &lt;strong&gt;~35 minutes&lt;/strong&gt; via a breaking-classified event — before support volume moved.&lt;/p&gt;

&lt;p&gt;That is the difference between &lt;strong&gt;consumer contract monitoring&lt;/strong&gt; and &lt;strong&gt;service health monitoring&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to add agent-loop checks
&lt;/h2&gt;

&lt;p&gt;If the failure is not "tool missing from catalog" but "agent keeps calling the wrong schema," embed drift checks closer to the loop — see &lt;a href="https://dev.to/kioiek/postmortem-well-add-mcp-monitoring-in-q3-embedding-driftguard-in-the-agent-loop-instead-dp9"&gt;agent embedding postmortem&lt;/a&gt;.&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;Export your current &lt;code&gt;tools/list&lt;/code&gt; JSON to &lt;code&gt;fixtures/mcp-baseline.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;drift-diff&lt;/code&gt; on PRs when that file changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://driftguard.org/start?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=dg-devto-mcp-contract-drift" rel="noopener noreferrer"&gt;Start a trial&lt;/a&gt;&lt;/strong&gt; on the one MCP URL you would page for at 2am.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; Do you version MCP tool catalogs today — git fixtures, vendor changelog only, or not at all? I read every reply; the answers shape the next post in this series.&lt;/p&gt;




&lt;h2&gt;
  
  
  Series links
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;Market gap / launch&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Why silent MCP drift happens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2"&gt;ToolSchema lab&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;10-minute hands-on demo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0"&gt;CI gate&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;GitHub Actions funnel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi"&gt;MCP tool removed postmortem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Real incident timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/postmortem-well-add-mcp-monitoring-in-q3-embedding-driftguard-in-the-agent-loop-instead-dp9"&gt;Agent embedding postmortem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MCP tools in the agent loop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Drift-Guard/driftguard" rel="noopener noreferrer"&gt;Drift-Guard/driftguard&lt;/a&gt; · Hosted: &lt;a href="https://driftguard.org" rel="noopener noreferrer"&gt;driftguard.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>cursor</category>
      <category>devtools</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Add a CI Gate for MCP Contract Coverage in 10 Minutes</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Thu, 18 Jun 2026 12:17:00 +0000</pubDate>
      <link>https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0</link>
      <guid>https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0</guid>
      <description>&lt;p&gt;Your PR is green. &lt;code&gt;tools/call&lt;/code&gt; still breaks on Tuesday.&lt;/p&gt;

&lt;p&gt;That gap is familiar: &lt;strong&gt;CI validates what you ship&lt;/strong&gt;, not &lt;strong&gt;what your agent consumes&lt;/strong&gt;. Cursor and Claude read &lt;code&gt;mcp.json&lt;/code&gt; (or &lt;code&gt;.cursor/mcp.json&lt;/code&gt;) and trust whatever &lt;code&gt;tools/list&lt;/code&gt; returns today. When a vendor removes a tool or tightens &lt;code&gt;inputSchema&lt;/code&gt;, your pipeline does not notice — because nothing in Git ever referenced that contract.&lt;/p&gt;

&lt;p&gt;We already covered the failure mode in &lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;why MCP integrations break silently&lt;/a&gt; and walked a hands-on lab in &lt;a href="https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2"&gt;ToolSchema Kit&lt;/a&gt;. This post is the &lt;strong&gt;CI half&lt;/strong&gt;: wire a progressive gate so every &lt;code&gt;mcp.json&lt;/code&gt; endpoint is either watched or explicitly ignored before merge.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you are adding
&lt;/h2&gt;

&lt;p&gt;DriftGuard CI is a &lt;strong&gt;hook → preview → trial → paid gate&lt;/strong&gt; funnel. You can stop at any layer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;API key&lt;/th&gt;
&lt;th&gt;Blocks CI?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1 — Hook&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;drift-diff&lt;/code&gt; / &lt;code&gt;compare_json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;On breaking fixture diff only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2 — Preview&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;drift-coverage-preview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No (writes Step Summary + trial link)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3 — Trial gate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;drift-coverage&lt;/code&gt; + trial session&lt;/td&gt;
&lt;td&gt;Trial secret&lt;/td&gt;
&lt;td&gt;Yes — &lt;strong&gt;1 endpoint&lt;/strong&gt; max&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4 — Pro gate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;drift-coverage&lt;/code&gt; + API key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dg_…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes — plan limit (50 on Pro)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Layer 2 is the fastest win: zero secrets, scans your repo, prints which MCP URLs are not monitored. Layer 4 is what teams adopt after one postmortem like &lt;a href="https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi"&gt;MCP tool removed over the weekend&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Full reference: &lt;a href="https://github.com/kioie/driftguard/blob/main/docs/CI.md" rel="noopener noreferrer"&gt;docs/CI.md&lt;/a&gt; in the open-source repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — Copy the starter workflow
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/driftguard.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DriftGuard&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schema-hook&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kioie/driftguard/.github/actions/drift-diff@v0.3.3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{"status":"ok","data":{"id":1,"name":"test"}}'&lt;/span&gt;
          &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{"status":"ok","data":{"id":1}}'&lt;/span&gt;

  &lt;span class="na"&gt;coverage-preview&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kioie/driftguard/.github/actions/drift-coverage-preview@v0.3.3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;scan-paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp.json,.cursor/mcp.json,package.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pin &lt;code&gt;@v0.3.3&lt;/code&gt;&lt;/strong&gt; (or current release) — never &lt;code&gt;@main&lt;/code&gt; in production pipelines.&lt;/p&gt;

&lt;p&gt;Open a PR. The &lt;strong&gt;DriftGuard&lt;/strong&gt; check runs two jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;schema-hook&lt;/strong&gt; — proves the diff action works (swap in your own before/after fixtures later).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;coverage-preview&lt;/strong&gt; — reads &lt;code&gt;scan-paths&lt;/code&gt;, discovers MCP and API URLs, writes a &lt;strong&gt;GitHub Step Summary&lt;/strong&gt; with unmonitored endpoints and one-click console links.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No &lt;code&gt;files-json&lt;/code&gt; boilerplate — &lt;code&gt;scan-paths&lt;/code&gt; walks the repo for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Read the Step Summary
&lt;/h2&gt;

&lt;p&gt;After the preview job finishes, expand &lt;strong&gt;Summary&lt;/strong&gt; on the workflow run. You should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Discovered endpoints: 3
Watched: 0
Missing: 3

→ https://driftguard.org/ci/setup?from=ci&amp;amp;import=…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That link opens &lt;strong&gt;&lt;a href="https://driftguard.org/ci/setup" rel="noopener noreferrer"&gt;CI setup&lt;/a&gt;&lt;/strong&gt;: mint a trial session, copy &lt;code&gt;DRIFTGUARD_TRIAL_SESSION&lt;/code&gt; into GitHub secrets, and import the first missing watch without leaving the browser.&lt;/p&gt;

&lt;p&gt;Preview is &lt;strong&gt;non-blocking by default&lt;/strong&gt; — it nudges without breaking existing repos. When you are ready to enforce, keep reading.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Trial gate (one endpoint)
&lt;/h2&gt;

&lt;p&gt;Add a secret &lt;code&gt;DRIFTGUARD_TRIAL_SESSION&lt;/code&gt; (from Step Summary or &lt;code&gt;POST /api/trial/session&lt;/code&gt;). Uncomment a third job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;coverage-gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kioie/driftguard/.github/actions/drift-coverage@v0.3.3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;trial-session&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DRIFTGUARD_TRIAL_SESSION }}&lt;/span&gt;
          &lt;span class="na"&gt;scan-paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp.json,.cursor/mcp.json,package.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Trial intentionally limits you to one watched endpoint.&lt;/strong&gt; If preview finds three MCP servers and only one is covered, the gate &lt;strong&gt;fails with an upgrade message&lt;/strong&gt;. That is the funnel working — not a bug.&lt;/p&gt;

&lt;p&gt;For a single-server team (one Stripe MCP, one internal ops server), trial gate is enough to block merges until that URL is on a schedule.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 — Pro gate (multi-dependency repos)
&lt;/h2&gt;

&lt;p&gt;After &lt;a href="https://driftguard.org/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt; → activate, replace the trial header with your API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;coverage-gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kioie/driftguard/.github/actions/drift-coverage@v0.3.3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DRIFTGUARD_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;scan-paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp.json,.cursor/mcp.json,package.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One &lt;code&gt;dg_…&lt;/code&gt; key unlocks &lt;strong&gt;assert_coverage&lt;/strong&gt; in MCP, the hosted API, and CI. Failures include &lt;code&gt;upgrade.console&lt;/code&gt; URLs to bulk-import missing watches.&lt;/p&gt;

&lt;p&gt;Local equivalent (useful in pre-commit or agent loops):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DRIFTGUARD_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dg_…
driftguard coverage assert &lt;span class="nt"&gt;--mcp-json&lt;/span&gt; .cursor/mcp.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit code &lt;strong&gt;1&lt;/strong&gt; when a discovered dependency is not watched.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this does &lt;em&gt;not&lt;/em&gt; replace
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;oasdiff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Diff &lt;strong&gt;your&lt;/strong&gt; OpenAPI specs at merge time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MockDrift / ToolChange&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gate packages for fixtures and MCP manifest lint — see &lt;a href="https://github.com/kioie/driftguard/blob/main/docs/policies/gate-ladder.md" rel="noopener noreferrer"&gt;gate ladder&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;APM / synthetics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Latency and 5xx on &lt;strong&gt;your&lt;/strong&gt; HTTP surface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The CI gate answers: &lt;strong&gt;"Every URL in mcp.json that our agents depend on — is it on a watch?"&lt;/strong&gt; Scheduled polling and breaking-classified alerts are hosted; the diff engine stays open source.&lt;/p&gt;




&lt;h2&gt;
  
  
  Suggested progression
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Week 1   drift-diff on PRs (fixture or snapshot you control)
Week 2   drift-coverage-preview (see the gap, no secrets)
Week 3   Trial gate on one critical MCP server
Week 4   Pro gate when preview lists 2+ production dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional: turn preview blocking early with &lt;code&gt;fail-on-missing: true&lt;/code&gt; once the team agrees every discovered URL should be watched or removed from config.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open core boundary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Free in GitHub Actions&lt;/th&gt;
&lt;th&gt;Hosted (trial / Pro)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;drift-diff&lt;/code&gt;, &lt;code&gt;compare_json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;register_watch&lt;/code&gt;, scheduled polls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;drift-coverage-preview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Alerts, drift history, console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step Summary + &lt;code&gt;/ci/setup&lt;/code&gt; deep links&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;assert_coverage&lt;/code&gt; enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Clone path until npm publish is fully wired: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;github.com/kioie/driftguard&lt;/a&gt; → &lt;code&gt;npm ci &amp;amp;&amp;amp; npm run build&lt;/code&gt;.&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;Copy &lt;a href="https://github.com/kioie/driftguard/blob/main/examples/workflows/driftguard-starter.yml" rel="noopener noreferrer"&gt;driftguard-starter.yml&lt;/a&gt; into your repo.&lt;/li&gt;
&lt;li&gt;Open a PR and read the Step Summary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://driftguard.org/start?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=ci-gate" rel="noopener noreferrer"&gt;Start a trial&lt;/a&gt;&lt;/strong&gt; if preview lists URLs you care about.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; Do you gate third-party dependencies in CI today — OpenAPI only, MCP included, or not at all? I read every reply and will link follow-up posts (agent embedding, contract drift monitoring) based on what teams are actually running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Series links
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;Market gap / launch&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Why silent MCP drift happens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2"&gt;ToolSchema lab&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;10-minute hands-on demo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi"&gt;MCP tool removed postmortem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Real incident timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/kioiek/postmortem-well-add-mcp-monitoring-in-q3-embedding-driftguard-in-the-agent-loop-instead-dp9"&gt;Agent embedding postmortem&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MCP tools in the agent loop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;kioie/driftguard&lt;/a&gt; · Hosted: &lt;a href="https://driftguard.org" rel="noopener noreferrer"&gt;driftguard.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>githubactions</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Catch MCP Tool-Schema Drift in 10 Minutes (Live Demo + Optional Watch)</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Fri, 05 Jun 2026 03:37:52 +0000</pubDate>
      <link>https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2</link>
      <guid>https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2</guid>
      <description>&lt;p&gt;Your agent stack can look healthy while the contract underneath it is already broken.&lt;/p&gt;

&lt;p&gt;HTTP &lt;code&gt;200&lt;/code&gt; on &lt;code&gt;/health&lt;/code&gt;. No failed deploys. CI green. Then &lt;code&gt;tools/call&lt;/code&gt; starts returning empty results because a maintainer renamed a parameter or removed a tool from &lt;code&gt;tools/list&lt;/code&gt; — and nobody pinned a baseline.&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;&lt;a href="https://github.com/kioie/toolschema-kit" rel="noopener noreferrer"&gt;ToolSchema Kit&lt;/a&gt;&lt;/strong&gt; as a small, reproducible lab for that failure mode: a Go MCP server with versioned tool output you can break on purpose. This walkthrough takes about &lt;strong&gt;10 minutes&lt;/strong&gt; and works entirely on the free hosted endpoint — no vendor API keys required.&lt;/p&gt;

&lt;p&gt;If you want continuous monitoring after the exercise, the last section shows how to point &lt;strong&gt;&lt;a href="https://driftguard.org" rel="noopener noreferrer"&gt;DriftGuard&lt;/a&gt;&lt;/strong&gt; at the same URL.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you will build
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Hit a live MCP catalog server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Connect Cursor and call &lt;code&gt;get_product&lt;/code&gt; / &lt;code&gt;list_skus&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Snapshot &lt;code&gt;tools/list&lt;/code&gt; as your contract baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Bump &lt;code&gt;CATALOG_SCHEMA_VERSION&lt;/code&gt; and see silent drift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;(Optional) Register a watch and get breaking alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Repos involved:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demo server: &lt;a href="https://github.com/kioie/toolschema-kit" rel="noopener noreferrer"&gt;github.com/kioie/toolschema-kit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Diff + MCP client: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;github.com/kioie/driftguard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hosted monitoring: &lt;a href="https://driftguard.org/start" rel="noopener noreferrer"&gt;driftguard.org/start&lt;/a&gt; (one free watch on trial)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why this matters (30-second context)
&lt;/h2&gt;

&lt;p&gt;OpenAPI teams already diff specs in CI with tools like &lt;a href="https://github.com/Tufin/oasdiff" rel="noopener noreferrer"&gt;OASDiff&lt;/a&gt;. MCP integrations rarely get the same discipline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tools/list&lt;/code&gt; is the closest thing to a published spec&lt;/li&gt;
&lt;li&gt;Vendors do not always changelog schema changes&lt;/li&gt;
&lt;li&gt;Agents swallow structured errors as retries or silence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ToolSchema Kit lets you &lt;strong&gt;practice&lt;/strong&gt; that gap locally before it happens with Stripe, GitHub, or your internal ops MCP.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — Use the live catalog MCP (no install)
&lt;/h2&gt;

&lt;p&gt;A free Render deployment is already running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://toolschema-kit.onrender.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Health check:&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; https://toolschema-kit.onrender.com/health
&lt;span class="c"&gt;# {"ok":true,"schema":"2026.06.01"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or run locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kioie/toolschema-kit.git
&lt;span class="nb"&gt;cd &lt;/span&gt;toolschema-kit
&lt;span class="nv"&gt;CATALOG_MCP_TRANSPORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http go run ./cmd/catalog-mcp
&lt;span class="c"&gt;# MCP: http://127.0.0.1:8080/mcp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server exposes two tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_product&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return a sample product record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_skus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List SKUs; output shape follows &lt;code&gt;CATALOG_SCHEMA_VERSION&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Step 2 — Connect Cursor
&lt;/h2&gt;

&lt;p&gt;Add to &lt;code&gt;.cursor/mcp.json&lt;/code&gt; (swap the URL for localhost if you ran locally):&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;"commerce-catalog"&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://toolschema-kit.onrender.com/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;Reload MCP in Cursor, then ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Call &lt;code&gt;get_product&lt;/code&gt; and &lt;code&gt;list_skus&lt;/code&gt;. Summarize the SKU fields you see.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should get a single SKU row under schema &lt;code&gt;2026.06.01&lt;/code&gt;. That happy path is what most teams stop testing after day one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Snapshot the contract
&lt;/h2&gt;

&lt;p&gt;Treat &lt;code&gt;tools/list&lt;/code&gt; like an OpenAPI file you version in git.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual snapshot&lt;/strong&gt; — save the JSON from your MCP inspector or agent session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With DriftGuard OSS&lt;/strong&gt; (local diff only, no account):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kioie/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm ci &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;compare_json&lt;/code&gt; via MCP or CLI when you have before/after payloads. The mental model: &lt;strong&gt;baseline now, diff later&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For production URLs, hosted DriftGuard stores that baseline and polls on a schedule — but the lab exercise works without signing up.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 — Simulate silent drift
&lt;/h2&gt;

&lt;p&gt;Schema version &lt;code&gt;2026.06.02&lt;/code&gt; changes &lt;code&gt;list_skus&lt;/code&gt; output: an extra SKU row and relabeled fields. HTTP health stays &lt;code&gt;{"ok":true}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CATALOG_SCHEMA_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2026.06.02 &lt;span class="nv"&gt;CATALOG_MCP_TRANSPORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http go run ./cmd/catalog-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-run &lt;code&gt;list_skus&lt;/code&gt; in Cursor. The agent may still succeed — but the JSON shape moved. That is &lt;strong&gt;silent drift&lt;/strong&gt;: no status-code alarm, broken downstream assumptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diff the two payloads&lt;/strong&gt; with DriftGuard CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run check &lt;span class="nt"&gt;--&lt;/span&gt; diff &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"schemaVersion":"2026.06.01","skus":[{"id":"sku-pro","label":"Pro"}]}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"schemaVersion":"2026.06.02","skus":[{"id":"sku-pro","label":"Pro Plan"},{"id":"sku-team","label":"Team"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example classification:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;What changed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Breaking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required field added/removed, tool removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Material description or type shift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Info&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;New optional field, new tool added&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Full version table: &lt;a href="https://github.com/kioie/toolschema-kit/blob/main/docs/simulate-drift.md" rel="noopener noreferrer"&gt;docs/simulate-drift.md&lt;/a&gt; in the kit repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — Optional: always-on watch
&lt;/h2&gt;

&lt;p&gt;When the exercise clicks, promote the same URL to a scheduled check.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://driftguard.org/start" rel="noopener noreferrer"&gt;Start a trial&lt;/a&gt;&lt;/strong&gt; — one watch, no card for the trial flow
&lt;/li&gt;
&lt;li&gt;Add an MCP watch on &lt;code&gt;https://toolschema-kit.onrender.com/mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open the &lt;a href="https://driftguard.org/console?demo=1" rel="noopener noreferrer"&gt;console demo&lt;/a&gt; to see breaking vs info events&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;From Cursor with DriftGuard MCP&lt;/strong&gt; (add API key to &lt;code&gt;env&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;"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;"driftguard"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"/absolute/path/to/driftguard/dist/mcp/server.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"DRIFTGUARD_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dg_…"&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;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;Useful tools: &lt;code&gt;register_watch&lt;/code&gt;, &lt;code&gt;check_watch&lt;/code&gt;, &lt;code&gt;list_drift_events&lt;/code&gt;. Offline tools (&lt;code&gt;compare_json&lt;/code&gt;, &lt;code&gt;parse_mcp_config&lt;/code&gt;, &lt;code&gt;hosted_info&lt;/code&gt;) work without a key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI gate&lt;/strong&gt; — assert every &lt;code&gt;mcp.json&lt;/code&gt; URL is watched before merge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DRIFTGUARD_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dg_…
driftguard coverage assert &lt;span class="nt"&gt;--mcp-json&lt;/span&gt; .cursor/mcp.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://github.com/kioie/toolschema-kit/blob/main/docs/ci.md" rel="noopener noreferrer"&gt;toolschema-kit CI docs&lt;/a&gt; and &lt;a href="https://github.com/kioie/driftguard/blob/main/examples/workflows/driftguard-starter.yml" rel="noopener noreferrer"&gt;driftguard starter workflow&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pattern: CI for what you own, watches for what you consume
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your OpenAPI specs     →  oasdiff in GitHub Actions
Partner + MCP URLs     →  DriftGuard watches + Slack/webhook
Lab fixtures (this demo) →  ToolSchema Kit version bumps in workshops
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That split keeps PR checks fast and puts long-running polling on infrastructure built for it.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;10-minute lab (free):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Point Cursor at &lt;code&gt;https://toolschema-kit.onrender.com/mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Call tools, snapshot &lt;code&gt;tools/list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Read &lt;a href="https://github.com/kioie/toolschema-kit/blob/main/docs/simulate-drift.md" rel="noopener noreferrer"&gt;simulate-drift.md&lt;/a&gt; and diff v1 vs v2 locally
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Production path:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OSS client: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;github.com/kioie/driftguard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hosted trial: &lt;a href="https://driftguard.org/start" rel="noopener noreferrer"&gt;driftguard.org/start&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Market context: &lt;a href="https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g"&gt;Why MCP integrations break silently&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Questions for the community
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Do you version &lt;code&gt;tools/list&lt;/code&gt; anywhere today, or only HTTP uptime?
&lt;/li&gt;
&lt;li&gt;Which MCP servers in your stack are owned by other teams?
&lt;/li&gt;
&lt;li&gt;Would a public catalog of “drift fixtures” like ToolSchema Kit be useful in your CI?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are expanding kit scenarios and watch defaults based on workshop feedback — issues and PRs welcome on both repos.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ToolSchema Kit is MIT — &lt;a href="https://github.com/kioie/toolschema-kit" rel="noopener noreferrer"&gt;github.com/kioie/toolschema-kit&lt;/a&gt;. DriftGuard open-core client — &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;github.com/kioie/driftguard&lt;/a&gt; · Hosted — &lt;a href="https://driftguard.org" rel="noopener noreferrer"&gt;driftguard.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>openapi</category>
    </item>
    <item>
      <title>Postmortem: \"We'll add MCP monitoring in Q3\" — embedding DriftGuard in the agent loop instead</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:27:07 +0000</pubDate>
      <link>https://dev.to/kioiek/postmortem-well-add-mcp-monitoring-in-q3-embedding-driftguard-in-the-agent-loop-instead-dp9</link>
      <guid>https://dev.to/kioiek/postmortem-well-add-mcp-monitoring-in-q3-embedding-driftguard-in-the-agent-loop-instead-dp9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Subtitle:&lt;/strong&gt; Replacing a multi-script monitoring design with MCP tools + CI assert&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The same customer above planned a &lt;strong&gt;internal&lt;/strong&gt; monitoring layer: cron jobs per vendor, S3 snapshots, custom severity rules, PagerDuty routing, and a quarterly review of MCP URLs in repos. Engineering estimate: &lt;strong&gt;~1.5 engineer-weeks&lt;/strong&gt; initial build, ongoing toil when MCP transport edge cases appeared.&lt;/p&gt;

&lt;p&gt;They cancelled that project after wiring &lt;strong&gt;DriftGuard's hosted API + MCP tools&lt;/strong&gt; into Cursor and CI. This post is a &lt;strong&gt;design postmortem&lt;/strong&gt; of the abandoned approach vs what shipped in two afternoons.&lt;/p&gt;

&lt;p&gt;Audience: teams googling &lt;em&gt;"monitor MCP tools/list changes"&lt;/em&gt;, &lt;em&gt;"detect removed MCP tool production"&lt;/em&gt;, or asking an AI &lt;em&gt;"how do I know when my agent's tools changed?"&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Intended architecture (never built)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cron per URL&lt;/td&gt;
&lt;td&gt;Periodic fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 (or D1) snapshot store&lt;/td&gt;
&lt;td&gt;History&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom diff&lt;/td&gt;
&lt;td&gt;JSON deep-compare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Severity heuristics&lt;/td&gt;
&lt;td&gt;Tool removed = ?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PagerDuty&lt;/td&gt;
&lt;td&gt;Route breaking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repo scanner&lt;/td&gt;
&lt;td&gt;Find new MCP URLs in PRs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runbook&lt;/td&gt;
&lt;td&gt;Interpret raw diffs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Failure modes they identified in design review:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP over &lt;strong&gt;SSE&lt;/strong&gt; vs plain HTTP (handshake, id matching)&lt;/li&gt;
&lt;li&gt;Distinguishing &lt;strong&gt;OpenAPI operation removal&lt;/strong&gt; from &lt;code&gt;info.version&lt;/code&gt; bumps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-traffic&lt;/strong&gt; endpoints never triggering in-app monitors&lt;/li&gt;
&lt;li&gt;Agent can't consume raw diff output—needs &lt;strong&gt;actionable&lt;/strong&gt; remediation text&lt;/li&gt;
&lt;li&gt;No single &lt;strong&gt;portfolio&lt;/strong&gt; view across Stripe + GitHub + N MCP servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They were rebuilding a subset of what DriftGuard already ships as a watchtower.&lt;/p&gt;




&lt;h2&gt;
  
  
  What they embedded instead
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Agent-readable contract (&lt;code&gt;/agents.md&lt;/code&gt;, &lt;code&gt;/llms.txt&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Cursor rule (paraphrased): &lt;em&gt;Before adding an MCP server or vendor OpenAPI URL, call &lt;code&gt;suggest_watches&lt;/code&gt;; before merge, ensure &lt;code&gt;assert_coverage&lt;/code&gt; passes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision automated:&lt;/strong&gt; "Did we forget to watch a new dependency?"&lt;br&gt;
&lt;strong&gt;Sophisticated alternative avoided:&lt;/strong&gt; Custom linter parsing &lt;code&gt;mcp.json&lt;/code&gt; in CI with team-specific rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. MCP tools (OSS client + API key)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Replaces&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suggest_watches&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manual spreadsheet of URLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;assert_coverage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Planned "repo scanner + policy" ticket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;explain_drift&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Senior engineer writing ticket descriptions from raw JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_drift_events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ad-hoc "what changed this week?" queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example interaction (real pattern, not scripted):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Engineer:&lt;/strong&gt; "CI failed on drift coverage — what's missing?"&lt;br&gt;
&lt;strong&gt;Agent:&lt;/strong&gt; Calls &lt;code&gt;assert_coverage&lt;/code&gt; with repo &lt;code&gt;mcp.json&lt;/code&gt; → returns &lt;code&gt;missing: [{ url, watchType: \"mcp\" }]&lt;/code&gt; → proposes &lt;code&gt;register_watch&lt;/code&gt; or asks to exclude with justification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Decision automated:&lt;/strong&gt; Block merge vs allow; no meeting about monitoring scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CI: &lt;code&gt;drift-coverage&lt;/code&gt; Action
&lt;/h3&gt;

&lt;p&gt;Scans committed files (including &lt;code&gt;mcp.json&lt;/code&gt;), calls hosted &lt;strong&gt;&lt;code&gt;/api/coverage/assert&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision automated:&lt;/strong&gt; New dependency in repo ⇒ must have watch (or CI fails).&lt;br&gt;
&lt;strong&gt;Sophisticated alternative avoided:&lt;/strong&gt; Org-wide service catalog + manual linking.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Optional: VS Code status bar extension
&lt;/h3&gt;

&lt;p&gt;Polls &lt;strong&gt;&lt;code&gt;/api/portfolio/overview&lt;/code&gt;&lt;/strong&gt; → shows health score + breaking count.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision informed:&lt;/strong&gt; "Do we deploy today?" without opening five dashboards.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario walkthrough: one PR, end to end
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; Developer adds a Notion MCP URL to &lt;code&gt;.cursor/mcp.json&lt;/code&gt; for a documentation agent.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;System behavior&lt;/th&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PR opened&lt;/td&gt;
&lt;td&gt;CI runs coverage assert&lt;/td&gt;
&lt;td&gt;Fail: URL not in watch list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer / agent&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;suggest_watches&lt;/code&gt; + create watch via API&lt;/td&gt;
&lt;td&gt;Watch registered; CI green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Dependency under external monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Later: Notion changes tool schema&lt;/td&gt;
&lt;td&gt;DriftGuard breaking event&lt;/td&gt;
&lt;td&gt;Slack + &lt;code&gt;agentAction&lt;/code&gt; in ticket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent reads &lt;code&gt;explain_drift&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Suggested code/prompt changes&lt;/td&gt;
&lt;td&gt;PR to fix integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without embedding: same PR merges; drift discovered in prod or never.&lt;/p&gt;




&lt;h2&gt;
  
  
  Search intents this setup is meant to catch
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Query (Google / ChatGPT)&lt;/th&gt;
&lt;th&gt;What the embedded flow gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCP tool removed how to detect&lt;/td&gt;
&lt;td&gt;MCP watch + breaking classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;monitor third party OpenAPI not mine&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;spec_format: openapi&lt;/code&gt; on vendor URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;schema drift webhook alert&lt;/td&gt;
&lt;td&gt;Hosted checks + Slack/webhook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prevent agent using stale MCP tools&lt;/td&gt;
&lt;td&gt;Coverage assert + drift on &lt;code&gt;tools/list&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stripe API changed field webhook&lt;/td&gt;
&lt;td&gt;OpenAPI watch on published spec URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alternative to monitoring vendor APIs cron&lt;/td&gt;
&lt;td&gt;Portfolio + suggest + ignore paths&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Tradeoffs (honest)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choose embedded DriftGuard&lt;/th&gt;
&lt;th&gt;Keep building in-house&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCP/OpenAPI semantics maintained upstream&lt;/td&gt;
&lt;td&gt;You own SSE, diff rules, retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portfolio UI + API day one&lt;/td&gt;
&lt;td&gt;You build dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-watch pricing&lt;/td&gt;
&lt;td&gt;Infra + on-call toil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent tools with stable severity model&lt;/td&gt;
&lt;td&gt;Agents invent severity from raw JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Still DIY:&lt;/strong&gt; monitoring &lt;strong&gt;your&lt;/strong&gt; service SLOs (Datadog/etc.). &lt;strong&gt;Still OSS/local:&lt;/strong&gt; diff &lt;strong&gt;your&lt;/strong&gt; spec in CI without hosted watches.&lt;/p&gt;




&lt;h2&gt;
  
  
  Outcome (customer-reported)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Internal "integration monitoring" epic closed as &lt;strong&gt;won't build&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mean time to &lt;strong&gt;understand&lt;/strong&gt; vendor/MCP change: hours → minutes&lt;/li&gt;
&lt;li&gt;New MCP URLs: caught at &lt;strong&gt;PR&lt;/strong&gt;, not post-deploy&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  If you're evaluating
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Reproduce the &lt;strong&gt;original&lt;/strong&gt; postmortem scenario on trial: two MCP or vendor URLs, run a check, wait for a drift event or simulate with a test fixture.&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;&lt;code&gt;assert_coverage&lt;/code&gt;&lt;/strong&gt; to one repo with &lt;code&gt;mcp.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Point your agent at &lt;strong&gt;&lt;code&gt;/agents.md&lt;/code&gt;&lt;/strong&gt; and see if it stops proposing cron+S3 designs.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;Console trial: &lt;a href="https://driftguard.eddy-d55.workers.dev/console" rel="noopener noreferrer"&gt;https://driftguard.eddy-d55.workers.dev/console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OSS + MCP client: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;https://github.com/kioie/driftguard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Agent docs: &lt;a href="https://driftguard.eddy-d55.workers.dev/agents.md" rel="noopener noreferrer"&gt;https://driftguard.eddy-d55.workers.dev/agents.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mcp</category>
      <category>devops</category>
      <category>postmortem</category>
      <category>ai</category>
    </item>
    <item>
      <title>Postmortem: MCP tool removed over the weekend, detected on scheduled poll (not prod traffic)</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:26:16 +0000</pubDate>
      <link>https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi</link>
      <guid>https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi</guid>
      <description>&lt;p&gt;&lt;strong&gt;Subtitle:&lt;/strong&gt; How a DriftGuard customer closed a gap their uptime stack and CI never covered&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;On 2026-05-12, a B2B SaaS team's Cursor-based workflow started failing intermittently: agents could read context but stopped creating tasks in their internal MCP server. Customer-facing APIs were healthy. Stripe webhooks and GitHub App installs showed no errors. The failure was isolated to &lt;strong&gt;a third-party MCP contract&lt;/strong&gt; the team depended on but did not operate.&lt;/p&gt;

&lt;p&gt;After adopting DriftGuard, a similar change was caught &lt;strong&gt;~35 minutes after the vendor's live &lt;code&gt;tools/list&lt;/code&gt; changed&lt;/strong&gt;, via a breaking-classified drift event and Slack alert—before support volume moved.&lt;/p&gt;

&lt;p&gt;This post walks through the original incident, why existing tooling missed it, and which DriftGuard capabilities map to each gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Impact (original incident)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Duration&lt;/td&gt;
&lt;td&gt;~4h from first user report to root cause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Severity&lt;/td&gt;
&lt;td&gt;SEV-2 (degraded agent workflows, API OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Affected&lt;/td&gt;
&lt;td&gt;Internal ops automations + one customer-facing "AI assistant" feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data loss&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revenue&lt;/td&gt;
&lt;td&gt;No direct billing impact; support load + delayed ship&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; MCP &lt;code&gt;tools/call&lt;/code&gt; errors and empty agent turns. Logs showed tool names that no longer existed in &lt;code&gt;tools/list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not affected:&lt;/strong&gt; Application HTTP error rates, p95 latency, Stripe charge success rate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Timeline (original incident, UTC)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sat 02:14&lt;/td&gt;
&lt;td&gt;Vendor deploys MCP server; &lt;code&gt;create_task&lt;/code&gt; removed from catalog (no public changelog)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sat–Mon&lt;/td&gt;
&lt;td&gt;No production traffic hits &lt;code&gt;create_task&lt;/code&gt; (low weekend usage)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mon 13:40&lt;/td&gt;
&lt;td&gt;Support ticket: "AI can't file tasks"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mon 14:10&lt;/td&gt;
&lt;td&gt;On-call checks &lt;strong&gt;service&lt;/strong&gt; dashboards — green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mon 15:05&lt;/td&gt;
&lt;td&gt;Engineer manually runs &lt;code&gt;curl&lt;/code&gt; + inspects MCP JSON; tool missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mon 16:00&lt;/td&gt;
&lt;td&gt;Hotfix: agent config updated to new tool name; incident closed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Detection gap:&lt;/strong&gt; ~62 hours from contract change to human discovery. Monitoring that only reflects &lt;strong&gt;your&lt;/strong&gt; traffic or &lt;strong&gt;your&lt;/strong&gt; release pipeline will not see this class of failure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Root cause
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Primary:&lt;/strong&gt; Undocumented removal of MCP tool &lt;code&gt;create_task&lt;/code&gt; from a server the team does not own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributing:&lt;/strong&gt; No baseline or diff on &lt;code&gt;tools/list&lt;/code&gt; / &lt;code&gt;inputSchema&lt;/code&gt; outside ad-hoc debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributing:&lt;/strong&gt; CI validates &lt;strong&gt;their&lt;/strong&gt; OpenAPI and contract tests use &lt;strong&gt;frozen fixtures&lt;/strong&gt; for vendor JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not an uptime problem. Endpoints returned 200. It is a &lt;strong&gt;consumer contract drift&lt;/strong&gt; problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why their stack didn't catch it
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it was doing&lt;/th&gt;
&lt;th&gt;Why it wasn't enough&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;APM / synthetics&lt;/td&gt;
&lt;td&gt;Latency and 5xx on &lt;strong&gt;their&lt;/strong&gt; API&lt;/td&gt;
&lt;td&gt;MCP schema isn't HTTP status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;oasdiff in CI&lt;/td&gt;
&lt;td&gt;Diff &lt;strong&gt;their&lt;/strong&gt; spec at merge&lt;/td&gt;
&lt;td&gt;Vendor MCP has no spec in repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cron &lt;code&gt;fetch&lt;/code&gt; + &lt;code&gt;jq&lt;/code&gt; (planned, never shipped)&lt;/td&gt;
&lt;td&gt;One URL, unstructured diff&lt;/td&gt;
&lt;td&gt;No MCP handshake, no breaking semantics, unmaintained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent retries&lt;/td&gt;
&lt;td&gt;Masked failures as "empty results"&lt;/td&gt;
&lt;td&gt;No alert; degraded UX&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The team needed &lt;strong&gt;continuous observation of external contracts&lt;/strong&gt; with &lt;strong&gt;breaking vs noise&lt;/strong&gt; classification—not another dashboard on their own service.&lt;/p&gt;




&lt;h2&gt;
  
  
  What they changed after the incident (DriftGuard mapping)
&lt;/h2&gt;

&lt;p&gt;Below is what the customer actually configured, and &lt;strong&gt;what decision each piece supported&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Inventory dependencies (day 0)
&lt;/h3&gt;

&lt;p&gt;They pasted repo &lt;code&gt;mcp.json&lt;/code&gt; and two OpenAPI URLs into the console &lt;strong&gt;import / suggest&lt;/strong&gt; flow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; Which URLs are worth watching first?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; Four watches proposed (2 MCP, Stripe OpenAPI, GitHub REST spec)—skipped debating a matrix in a spreadsheet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Watch types and intervals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MCP servers: &lt;code&gt;watchType: mcp&lt;/code&gt;, 30-minute interval&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vendor OpenAPI specs: &lt;code&gt;specFormat: openapi&lt;/code&gt;, daily interval&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Where do we need fast feedback vs slow spec churn?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; MCP on shorter interval; OpenAPI vendors on daily (semantic op-level diff, not raw JSON tree noise).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Baseline + fingerprint
&lt;/h3&gt;

&lt;p&gt;First manual &lt;strong&gt;check&lt;/strong&gt; on each watch stored a snapshot and &lt;strong&gt;schema fingerprint&lt;/strong&gt; on the watch row.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; Has this contract changed since we last looked?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; Fleet view shows stable hash; drift events are diffs against a known baseline, not one-off curls.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Alert routing
&lt;/h3&gt;

&lt;p&gt;Slack incoming webhook on MCP watches; &lt;strong&gt;breaking-only&lt;/strong&gt; policy initially.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; Who gets paged for what?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; &lt;code&gt;#integrations&lt;/code&gt; channel; &lt;strong&gt;test ping&lt;/strong&gt; confirmed delivery (&lt;code&gt;webhook_last_status&lt;/code&gt; visible in console—important for trusting alerts).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Ignore paths on Stripe watch
&lt;/h3&gt;

&lt;p&gt;Ignored &lt;code&gt;$.info.version&lt;/code&gt; after a noisy warning.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; Is this alert actionable?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; Team kept breaking alerts on operations; suppressed metadata churn.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. CI gate
&lt;/h3&gt;

&lt;p&gt;GitHub Action calling &lt;strong&gt;&lt;code&gt;/api/coverage/assert&lt;/code&gt;&lt;/strong&gt; on &lt;code&gt;mcp.json&lt;/code&gt; in the repo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; Can we prevent &lt;em&gt;new&lt;/em&gt; unwatched deps from merging?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; PR adding a third MCP URL failed CI until a watch existed—addresses repeat of "we added a dep but forgot to monitor it."&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Second event (after DriftGuard)—how it played out
&lt;/h2&gt;

&lt;p&gt;Two weeks later, the &lt;strong&gt;same&lt;/strong&gt; internal MCP server renamed a tool (warning-level add + breaking-level required field on another tool in staging—not prod yet, but live URL).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;09:12&lt;/td&gt;
&lt;td&gt;DriftGuard scheduled check runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:12&lt;/td&gt;
&lt;td&gt;Drift event: 1 breaking, 2 warnings on MCP watch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:13&lt;/td&gt;
&lt;td&gt;Slack alert delivered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:20&lt;/td&gt;
&lt;td&gt;Engineer opens &lt;strong&gt;drift timeline&lt;/strong&gt; → watch detail&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The drift payload included &lt;strong&gt;&lt;code&gt;agentAction&lt;/code&gt;&lt;/strong&gt; strings (e.g. update client calls for required field on &lt;code&gt;tools.sync_tasks.inputSchema&lt;/code&gt;). That text went straight into the Jira ticket—no separate "write up what changed" step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time to detect:&lt;/strong&gt; ~35 minutes (poll interval + cron), not 62 hours.&lt;br&gt;
&lt;strong&gt;Time to understand:&lt;/strong&gt; minutes (classified diff + explain), not half a day of manual JSON comparison.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons learned (customer's words, paraphrased)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consumer contracts need consumer monitoring.&lt;/strong&gt; CI on your repo cannot substitute for watches on URLs you call but don't control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP failures look like agent bugs.&lt;/strong&gt; Without &lt;code&gt;tools/list&lt;/code&gt; diffs, on-call burns time in the wrong layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classification matters.&lt;/strong&gt; "JSON changed" alerts get ignored; &lt;strong&gt;breaking tool removal&lt;/strong&gt; gets fixed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage is a process problem.&lt;/strong&gt; Assert-on-merge turned monitoring from heroics into a default.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  When this pattern applies to you
&lt;/h2&gt;

&lt;p&gt;Consider the same approach if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You run agents against &lt;strong&gt;MCP servers you don't operate&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You integrate Stripe/GitHub/partner APIs from &lt;strong&gt;live&lt;/strong&gt; behavior, not specs you pin in CI&lt;/li&gt;
&lt;li&gt;You have &lt;strong&gt;low-traffic&lt;/strong&gt; code paths that won't trip synthetics until Monday&lt;/li&gt;
&lt;li&gt;You've said "we should cron those URLs someday" and never did&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not a fit if:&lt;/strong&gt; you only need to gate &lt;strong&gt;your own&lt;/strong&gt; OpenAPI at release—use the OSS diff / GitHub Action locally; DriftGuard's hosted value is &lt;strong&gt;external&lt;/strong&gt; watches.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Console trial (2 real watches): &lt;a href="https://driftguard.eddy-d55.workers.dev/console" rel="noopener noreferrer"&gt;https://driftguard.eddy-d55.workers.dev/console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OSS + MCP client: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;https://github.com/kioie/driftguard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;API / agent docs: &lt;code&gt;/openapi.json&lt;/code&gt;, &lt;code&gt;/agents.md&lt;/code&gt;, &lt;code&gt;/llms.txt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mcp</category>
      <category>devops</category>
      <category>postmortem</category>
      <category>api</category>
    </item>
    <item>
      <title>Why Your MCP Integrations Break Silently — And How We Built DriftGuard to Close the Gap</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Sat, 30 May 2026 02:50:51 +0000</pubDate>
      <link>https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g</link>
      <guid>https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g</guid>
      <description>&lt;p&gt;Every integration team has lived the same incident: &lt;strong&gt;a dependency changed its contract, nothing failed in CI, and production broke on a Tuesday anyway.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When Optic shut down, that pain got louder. Teams still need to know when an API they depend on — but do not own — starts returning different JSON. What changed in the last six months is volume and surface area: &lt;strong&gt;MCP servers, agent tool catalogs, and partner webhooks&lt;/strong&gt; now fail the same way REST APIs always have, except failures show up as confused agents instead of clean &lt;code&gt;4xx&lt;/code&gt; errors.&lt;/p&gt;

&lt;p&gt;We built &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;DriftGuard&lt;/a&gt; because the tooling landscape left a hole:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What teams use today&lt;/th&gt;
&lt;th&gt;What it covers well&lt;/th&gt;
&lt;th&gt;What it misses&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;oasdiff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OpenAPI diffs in CI for specs you control&lt;/td&gt;
&lt;td&gt;Live payloads, MCP tools, vendors without specs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FlareCanary / uptime tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Status codes, latency&lt;/td&gt;
&lt;td&gt;Schema shape, required fields, tool definitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contract tests in-repo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your own services&lt;/td&gt;
&lt;td&gt;Stripe, GitHub, internal MCP servers owned by other teams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The gap:&lt;/strong&gt; continuous monitoring for &lt;strong&gt;schema drift&lt;/strong&gt; on systems you consume but do not publish specs for — especially &lt;strong&gt;MCP &lt;code&gt;tools/list&lt;/code&gt; output&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article walks through the problems we see in production integrations, how we classify drift, and how to wire monitoring into a stack you already run.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problems integration teams actually hit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. MCP tools change without a changelog
&lt;/h3&gt;

&lt;p&gt;Your agent stack depends on tools like &lt;code&gt;create_pull_request&lt;/code&gt;, &lt;code&gt;search_code&lt;/code&gt;, or an internal ops MCP server. When a maintainer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;removes a tool,&lt;/li&gt;
&lt;li&gt;adds a &lt;strong&gt;required&lt;/strong&gt; field to &lt;code&gt;inputSchema&lt;/code&gt;, or&lt;/li&gt;
&lt;li&gt;renames a parameter,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the agent does not always surface a structured error. You get retries, empty results, or silent tool skips. By the time someone notices, several workflows have already degraded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teams need:&lt;/strong&gt; a baseline snapshot of &lt;code&gt;tools/list&lt;/code&gt; and a diff when the catalog or schemas move.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Vendor APIs drift outside your OpenAPI file
&lt;/h3&gt;

&lt;p&gt;Stripe webhooks, GitHub REST responses, billing portals, identity providers — most teams integrate against &lt;strong&gt;observed JSON&lt;/strong&gt;, not a spec they version in-repo. A field disappears, a type widens, an array becomes an object. Unit tests with fixtures go stale; production does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teams need:&lt;/strong&gt; infer schema from live responses over time and alert on &lt;strong&gt;breaking&lt;/strong&gt; vs &lt;strong&gt;informational&lt;/strong&gt; changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CI green, production red
&lt;/h3&gt;

&lt;p&gt;Contract tests validate what you &lt;em&gt;ship&lt;/em&gt;. They rarely validate what you &lt;em&gt;consume&lt;/em&gt;. Post-Optic, teams rebuilt CI diff pipelines but still lack &lt;strong&gt;always-on watches&lt;/strong&gt; on URLs that matter for revenue or operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teams need:&lt;/strong&gt; scheduled checks, webhook alerts, and history — without running another JVM cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  How we approach schema drift at DriftGuard
&lt;/h2&gt;

&lt;p&gt;Our platform monitors two watch types:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;REST / JSON endpoints&lt;/strong&gt; — fetch, infer schema, diff against the last snapshot
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP servers&lt;/strong&gt; — &lt;code&gt;initialize&lt;/code&gt; → &lt;code&gt;tools/list&lt;/code&gt;, diff tool names and &lt;code&gt;inputSchema&lt;/code&gt; over time
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every change lands in one of three buckets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Breaking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Callers or agents will fail&lt;/td&gt;
&lt;td&gt;Required field added, tool removed, type narrowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Likely breakage or silent behavior change&lt;/td&gt;
&lt;td&gt;Optional field removed, tool description changed materially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Info&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Safe evolution&lt;/td&gt;
&lt;td&gt;New optional field, new tool added&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That classification is what makes alerts actionable. On-call does not need a raw JSON diff at 2am — they need to know if they can wait until Monday.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local diff (no account required)
&lt;/h3&gt;

&lt;p&gt;Teams can validate the engine locally before pointing watches at production URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kioie/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build

npm run check &lt;span class="nt"&gt;--&lt;/span&gt; diff &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"user":{"id":1,"email":"a@b.com"}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"user":{"id":1}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output shape:&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;"hasChanges"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breakingCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warningCount"&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;"infoCount"&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;"changes"&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="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;field-level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;detail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;Use this in incident post-mortems, vendor escalation threads, or pre-deploy sanity checks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical deployment patterns we recommend
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pattern A — CI for what you own, watches for what you don't
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your OpenAPI specs  →  oasdiff in GitHub Actions
Partner / MCP URLs  →  DriftGuard watches + webhooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This split keeps CI fast and puts long-running polling on infrastructure built for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern B — MCP-native operations
&lt;/h3&gt;

&lt;p&gt;DriftGuard ships an MCP server so agent workflows can register and inspect watches without context-switching to a dashboard:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Use when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;compare_json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ad-hoc diff of two payloads (runs locally)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;register_watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a URL to continuous monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;check_watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force an immediate drift check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_drift_events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull recent breaking changes into an agent session&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We designed this so platform teams can expose drift data &lt;strong&gt;inside&lt;/strong&gt; the same surface engineers already use — not as another portal login.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern C — Alert routing you already have
&lt;/h3&gt;

&lt;p&gt;Point watch webhooks at Slack, PagerDuty, or an internal event bus. Payloads include breaking / warning / info counts plus structured change lists so routers can page only on &lt;code&gt;breakingCount &amp;gt; 0&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hosted platform vs open-source client
&lt;/h2&gt;

&lt;p&gt;We run an open-core model: the diff engine and MCP client are public; continuous monitoring, retention, and multi-tenant isolation run on our hosted edge stack.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Built for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Self-host, 3 watches, daily checks, OSS MCP + CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$39/mo ($29 founding)&lt;/td&gt;
&lt;td&gt;50 watches, 30-min checks, breaking webhooks, 90-day history + export, health API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Team&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$99/mo&lt;/td&gt;
&lt;td&gt;200 watches, 5-min checks, 1-year retention, bulk export, priority support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hosted checkout and billing are handled through our secure payment flow — no separate ops burden for tax or invoicing on your side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started on hosted:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://driftguard.eddy-d55.workers.dev/pricing" rel="noopener noreferrer"&gt;Pricing &amp;amp; checkout&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://driftguard.eddy-d55.workers.dev/activate" rel="noopener noreferrer"&gt;Activate API key&lt;/a&gt; after purchase
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;DRIFTGUARD_API_KEY&lt;/code&gt; to your MCP or CI environment (see &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;README&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Where DriftGuard fits in the market
&lt;/h2&gt;

&lt;p&gt;We are not replacing oasdiff — we are complementing it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;oasdiff&lt;/strong&gt; → gate merges on spec changes you control
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DriftGuard&lt;/strong&gt; → watch runtime behavior of APIs and MCP tools you depend on
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your roadmap includes more agents, more MCP integrations, or more vendor APIs post-Optic, schema drift becomes infrastructure work — not a one-off debugging session.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Open source (5 minutes):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kioie/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build
npm run check &lt;span class="nt"&gt;--&lt;/span&gt; diff &lt;span class="s1"&gt;'&amp;lt;before-json&amp;gt;'&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;after-json&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hosted monitoring:&lt;/strong&gt; register your first watch from Cursor via MCP or POST to &lt;code&gt;/api/watches&lt;/code&gt; with a Pro API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions we want from the community:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which MCP servers are you running in production today?
&lt;/li&gt;
&lt;li&gt;Do you page on schema drift, or only on HTTP errors?
&lt;/li&gt;
&lt;li&gt;What would make hosted monitoring a no-brainer vs self-host?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are actively expanding MCP coverage and retention policies based on production feedback from early teams.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;DriftGuard is maintained by the team at &lt;a href="https://github.com/kioie" rel="noopener noreferrer"&gt;Kioi&lt;/a&gt;. Open-source client: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;github.com/kioie/driftguard&lt;/a&gt; · Hosted: &lt;a href="https://driftguard.eddy-d55.workers.dev" rel="noopener noreferrer"&gt;driftguard.eddy-d55.workers.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>mcp</category>
      <category>devops</category>
      <category>api</category>
    </item>
    <item>
      <title>Why Your MCP Integrations Break Silently — And How We Built DriftGuard to Close the Gap</title>
      <dc:creator>Kioi</dc:creator>
      <pubDate>Fri, 29 May 2026 19:54:45 +0000</pubDate>
      <link>https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4m6g</link>
      <guid>https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4m6g</guid>
      <description>&lt;p&gt;Every integration team has lived the same incident: &lt;strong&gt;a dependency changed its contract, nothing failed in CI, and production broke on a Tuesday anyway.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When Optic shut down, that pain got louder. Teams still need to know when an API they depend on — but do not own — starts returning different JSON. What changed in the last six months is volume and surface area: &lt;strong&gt;MCP servers, agent tool catalogs, and partner webhooks&lt;/strong&gt; now fail the same way REST APIs always have, except failures show up as confused agents instead of clean &lt;code&gt;4xx&lt;/code&gt; errors.&lt;/p&gt;

&lt;p&gt;We built &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;DriftGuard&lt;/a&gt; because the tooling landscape left a hole:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What teams use today&lt;/th&gt;
&lt;th&gt;What it covers well&lt;/th&gt;
&lt;th&gt;What it misses&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;oasdiff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OpenAPI diffs in CI for specs you control&lt;/td&gt;
&lt;td&gt;Live payloads, MCP tools, vendors without specs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FlareCanary / uptime tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Status codes, latency&lt;/td&gt;
&lt;td&gt;Schema shape, required fields, tool definitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contract tests in-repo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your own services&lt;/td&gt;
&lt;td&gt;Stripe, GitHub, internal MCP servers owned by other teams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The gap:&lt;/strong&gt; continuous monitoring for &lt;strong&gt;schema drift&lt;/strong&gt; on systems you consume but do not publish specs for — especially &lt;strong&gt;MCP &lt;code&gt;tools/list&lt;/code&gt; output&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article walks through the problems we see in production integrations, how we classify drift, and how to wire monitoring into a stack you already run.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problems integration teams actually hit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. MCP tools change without a changelog
&lt;/h3&gt;

&lt;p&gt;Your agent stack depends on tools like &lt;code&gt;create_pull_request&lt;/code&gt;, &lt;code&gt;search_code&lt;/code&gt;, or an internal ops MCP server. When a maintainer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;removes a tool,&lt;/li&gt;
&lt;li&gt;adds a &lt;strong&gt;required&lt;/strong&gt; field to &lt;code&gt;inputSchema&lt;/code&gt;, or&lt;/li&gt;
&lt;li&gt;renames a parameter,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the agent does not always surface a structured error. You get retries, empty results, or silent tool skips. By the time someone notices, several workflows have already degraded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teams need:&lt;/strong&gt; a baseline snapshot of &lt;code&gt;tools/list&lt;/code&gt; and a diff when the catalog or schemas move.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Vendor APIs drift outside your OpenAPI file
&lt;/h3&gt;

&lt;p&gt;Stripe webhooks, GitHub REST responses, billing portals, identity providers — most teams integrate against &lt;strong&gt;observed JSON&lt;/strong&gt;, not a spec they version in-repo. A field disappears, a type widens, an array becomes an object. Unit tests with fixtures go stale; production does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teams need:&lt;/strong&gt; infer schema from live responses over time and alert on &lt;strong&gt;breaking&lt;/strong&gt; vs &lt;strong&gt;informational&lt;/strong&gt; changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CI green, production red
&lt;/h3&gt;

&lt;p&gt;Contract tests validate what you &lt;em&gt;ship&lt;/em&gt;. They rarely validate what you &lt;em&gt;consume&lt;/em&gt;. Post-Optic, teams rebuilt CI diff pipelines but still lack &lt;strong&gt;always-on watches&lt;/strong&gt; on URLs that matter for revenue or operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teams need:&lt;/strong&gt; scheduled checks, webhook alerts, and history — without running another JVM cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  How we approach schema drift at DriftGuard
&lt;/h2&gt;

&lt;p&gt;Our platform monitors two watch types:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;REST / JSON endpoints&lt;/strong&gt; — fetch, infer schema, diff against the last snapshot
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP servers&lt;/strong&gt; — &lt;code&gt;initialize&lt;/code&gt; → &lt;code&gt;tools/list&lt;/code&gt;, diff tool names and &lt;code&gt;inputSchema&lt;/code&gt; over time
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every change lands in one of three buckets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Breaking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Callers or agents will fail&lt;/td&gt;
&lt;td&gt;Required field added, tool removed, type narrowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Likely breakage or silent behavior change&lt;/td&gt;
&lt;td&gt;Optional field removed, tool description changed materially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Info&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Safe evolution&lt;/td&gt;
&lt;td&gt;New optional field, new tool added&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That classification is what makes alerts actionable. On-call does not need a raw JSON diff at 2am — they need to know if they can wait until Monday.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local diff (no account required)
&lt;/h3&gt;

&lt;p&gt;Teams can validate the engine locally before pointing watches at production URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kioie/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build

npm run check &lt;span class="nt"&gt;--&lt;/span&gt; diff &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"user":{"id":1,"email":"a@b.com"}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"user":{"id":1}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output shape:&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;"hasChanges"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breakingCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warningCount"&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;"infoCount"&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;"changes"&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="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;field-level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;detail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;Use this in incident post-mortems, vendor escalation threads, or pre-deploy sanity checks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical deployment patterns we recommend
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pattern A — CI for what you own, watches for what you don't
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your OpenAPI specs  →  oasdiff in GitHub Actions
Partner / MCP URLs  →  DriftGuard watches + webhooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This split keeps CI fast and puts long-running polling on infrastructure built for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern B — MCP-native operations
&lt;/h3&gt;

&lt;p&gt;DriftGuard ships an MCP server so agent workflows can register and inspect watches without context-switching to a dashboard:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Use when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;compare_json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ad-hoc diff of two payloads (runs locally)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;register_watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a URL to continuous monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;check_watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force an immediate drift check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_drift_events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull recent breaking changes into an agent session&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We designed this so platform teams can expose drift data &lt;strong&gt;inside&lt;/strong&gt; the same surface engineers already use — not as another portal login.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern C — Alert routing you already have
&lt;/h3&gt;

&lt;p&gt;Point watch webhooks at Slack, PagerDuty, or an internal event bus. Payloads include breaking / warning / info counts plus structured change lists so routers can page only on &lt;code&gt;breakingCount &amp;gt; 0&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hosted platform vs open-source client
&lt;/h2&gt;

&lt;p&gt;We run an open-core model: the diff engine and MCP client are public; continuous monitoring, retention, and multi-tenant isolation run on our hosted edge stack.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Built for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Self-host, 3 watches, daily checks, OSS MCP + CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$19/mo&lt;/td&gt;
&lt;td&gt;25 watches, hourly checks, 30-day history, API keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Team&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$49/mo&lt;/td&gt;
&lt;td&gt;100 watches, 15-minute checks, shared keys, priority support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hosted checkout and billing are handled through our secure payment flow — no separate ops burden for tax or invoicing on your side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started on hosted:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://driftguard.eddy-d55.workers.dev/pricing" rel="noopener noreferrer"&gt;Pricing &amp;amp; checkout&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://driftguard.eddy-d55.workers.dev/activate" rel="noopener noreferrer"&gt;Activate API key&lt;/a&gt; after purchase
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;DRIFTGUARD_API_KEY&lt;/code&gt; to your MCP or CI environment (see &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;README&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Where DriftGuard fits in the market
&lt;/h2&gt;

&lt;p&gt;We are not replacing oasdiff — we are complementing it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;oasdiff&lt;/strong&gt; → gate merges on spec changes you control
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DriftGuard&lt;/strong&gt; → watch runtime behavior of APIs and MCP tools you depend on
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your roadmap includes more agents, more MCP integrations, or more vendor APIs post-Optic, schema drift becomes infrastructure work — not a one-off debugging session.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Open source (5 minutes):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kioie/driftguard
&lt;span class="nb"&gt;cd &lt;/span&gt;driftguard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build
npm run check &lt;span class="nt"&gt;--&lt;/span&gt; diff &lt;span class="s1"&gt;'&amp;lt;before-json&amp;gt;'&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;after-json&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hosted monitoring:&lt;/strong&gt; register your first watch from Cursor via MCP or POST to &lt;code&gt;/api/watches&lt;/code&gt; with a Pro API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions we want from the community:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which MCP servers are you running in production today?
&lt;/li&gt;
&lt;li&gt;Do you page on schema drift, or only on HTTP errors?
&lt;/li&gt;
&lt;li&gt;What would make hosted monitoring a no-brainer vs self-host?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are actively expanding MCP coverage and retention policies based on production feedback from early teams.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;DriftGuard is maintained by the team at &lt;a href="https://github.com/kioie" rel="noopener noreferrer"&gt;Kioi&lt;/a&gt;. Open-source client: &lt;a href="https://github.com/kioie/driftguard" rel="noopener noreferrer"&gt;github.com/kioie/driftguard&lt;/a&gt; · Hosted: &lt;a href="https://driftguard.eddy-d55.workers.dev" rel="noopener noreferrer"&gt;driftguard.eddy-d55.workers.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>mcp</category>
      <category>devops</category>
      <category>api</category>
    </item>
  </channel>
</rss>
