<?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>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>
