{"slug": "add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes", "title": "Add a CI Gate for MCP Contract Coverage in 10 Minutes", "summary": "DriftGuard offers a CI gate that catches silent MCP contract drift before merge. The tool scans mcp.json files, compares tool schemas, and blocks pull requests when endpoints are missing or changed. A progressive funnel lets teams start with a free preview and upgrade to a paid gate that enforces coverage.", "body_md": "Your PR is green. `tools/call`\n\nstill breaks on Tuesday.\n\nThat gap is familiar: **CI validates what you ship**, not **what your agent consumes**. Cursor and Claude read `mcp.json`\n\n(or `.cursor/mcp.json`\n\n) and trust whatever `tools/list`\n\nreturns today. When a vendor removes a tool or tightens `inputSchema`\n\n, your pipeline does not notice — because nothing in Git ever referenced that contract.\n\nWe already covered the failure mode in [why MCP integrations break silently](https://dev.to/kioiek/why-your-mcp-integrations-break-silently-and-how-we-built-driftguard-to-close-the-gap-4g0g) and walked a hands-on lab in [ToolSchema Kit](https://dev.to/kioiek/catch-mcp-tool-schema-drift-in-10-minutes-live-demo-optional-watch-4ao2). This post is the **CI half**: wire a progressive gate so every `mcp.json`\n\nendpoint is either watched or explicitly ignored before merge.\n\nDriftGuard CI is a **hook → preview → trial → paid gate** funnel. You can stop at any layer:\n\n| Layer | Action | API key | Blocks CI? |\n|---|---|---|---|\n1 — Hook |\n`drift-diff` / `compare_json`\n|\nNo | On breaking fixture diff only |\n2 — Preview |\n`drift-coverage-preview` |\nNo | No (writes Step Summary + trial link) |\n3 — Trial gate |\n`drift-coverage` + trial session |\nTrial secret | Yes — 1 endpoint max |\n4 — Pro gate |\n`drift-coverage` + API key |\n`dg_…` |\nYes — plan limit (50 on Pro) |\n\nLayer 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 [MCP tool removed over the weekend](https://dev.to/kioiek/postmortem-mcp-tool-removed-over-the-weekend-detected-on-scheduled-poll-not-prod-traffic-1pdi).\n\nFull reference: [docs/CI.md](https://github.com/kioie/driftguard/blob/main/docs/CI.md) in the open-source repo.\n\nCreate `.github/workflows/driftguard.yml`\n\n:\n\n```\nname: DriftGuard\n\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  schema-hook:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: kioie/driftguard/.github/actions/drift-diff@v0.3.3\n        with:\n          before: '{\"status\":\"ok\",\"data\":{\"id\":1,\"name\":\"test\"}}'\n          after: '{\"status\":\"ok\",\"data\":{\"id\":1}}'\n\n  coverage-preview:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: kioie/driftguard/.github/actions/drift-coverage-preview@v0.3.3\n        with:\n          scan-paths: mcp.json,.cursor/mcp.json,package.json\n```\n\n**Pin @v0.3.3** (or current release) — never\n\n`@main`\n\nin production pipelines.Open a PR. The **DriftGuard** check runs two jobs:\n\n`scan-paths`\n\n, discovers MCP and API URLs, writes a No `files-json`\n\nboilerplate — `scan-paths`\n\nwalks the repo for you.\n\nAfter the preview job finishes, expand **Summary** on the workflow run. You should see something like:\n\n```\nDiscovered endpoints: 3\nWatched: 0\nMissing: 3\n\n→ https://driftguard.org/ci/setup?from=ci&import=…\n```\n\nThat link opens ** CI setup**: mint a trial session, copy\n\n`DRIFTGUARD_TRIAL_SESSION`\n\ninto GitHub secrets, and import the first missing watch without leaving the browser.Preview is **non-blocking by default** — it nudges without breaking existing repos. When you are ready to enforce, keep reading.\n\nAdd a secret `DRIFTGUARD_TRIAL_SESSION`\n\n(from Step Summary or `POST /api/trial/session`\n\n). Uncomment a third job:\n\n```\n  coverage-gate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: kioie/driftguard/.github/actions/drift-coverage@v0.3.3\n        with:\n          trial-session: ${{ secrets.DRIFTGUARD_TRIAL_SESSION }}\n          scan-paths: mcp.json,.cursor/mcp.json,package.json\n```\n\n**Trial intentionally limits you to one watched endpoint.** If preview finds three MCP servers and only one is covered, the gate **fails with an upgrade message**. That is the funnel working — not a bug.\n\nFor 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.\n\nAfter [pricing](https://driftguard.org/pricing) → activate, replace the trial header with your API key:\n\n```\n  coverage-gate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: kioie/driftguard/.github/actions/drift-coverage@v0.3.3\n        with:\n          api-key: ${{ secrets.DRIFTGUARD_API_KEY }}\n          scan-paths: mcp.json,.cursor/mcp.json,package.json\n```\n\nOne `dg_…`\n\nkey unlocks **assert_coverage** in MCP, the hosted API, and CI. Failures include `upgrade.console`\n\nURLs to bulk-import missing watches.\n\nLocal equivalent (useful in pre-commit or agent loops):\n\n```\nexport DRIFTGUARD_API_KEY=dg_…\ndriftguard coverage assert --mcp-json .cursor/mcp.json\n```\n\nExit code **1** when a discovered dependency is not watched.\n\n| Tool | Role |\n|---|---|\noasdiff |\nDiff your OpenAPI specs at merge time |\nMockDrift / ToolChange |\nGate packages for fixtures and MCP manifest lint — see\n|\n\nThe CI gate answers: **\"Every URL in mcp.json that our agents depend on — is it on a watch?\"** Scheduled polling and breaking-classified alerts are hosted; the diff engine stays open source.\n\n```\nWeek 1   drift-diff on PRs (fixture or snapshot you control)\nWeek 2   drift-coverage-preview (see the gap, no secrets)\nWeek 3   Trial gate on one critical MCP server\nWeek 4   Pro gate when preview lists 2+ production dependencies\n```\n\nOptional: turn preview blocking early with `fail-on-missing: true`\n\nonce the team agrees every discovered URL should be watched or removed from config.\n\n| Free in GitHub Actions | Hosted (trial / Pro) |\n|---|---|\n`drift-diff` , `compare_json`\n|\n`register_watch` , scheduled polls |\n`drift-coverage-preview` |\nAlerts, drift history, console |\nStep Summary + `/ci/setup` deep links |\n`assert_coverage` enforcement |\n\nClone path until npm publish is fully wired: [github.com/kioie/driftguard](https://github.com/kioie/driftguard) → `npm ci && npm run build`\n\n.\n\n**Question for you:** 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.\n\n| Post | Topic |\n|---|---|\n|\n\nGitHub: [kioie/driftguard](https://github.com/kioie/driftguard) · Hosted: [driftguard.org](https://driftguard.org)", "url": "https://wpnews.pro/news/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes", "canonical_source": "https://dev.to/kioiek/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes-2ga0", "published_at": "2026-06-18 12:17:00+00:00", "updated_at": "2026-06-18 12:21:15.156235+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "large-language-models"], "entities": ["DriftGuard", "Cursor", "Claude", "GitHub Actions", "MCP"], "alternates": {"html": "https://wpnews.pro/news/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes", "markdown": "https://wpnews.pro/news/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes.md", "text": "https://wpnews.pro/news/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes.txt", "jsonld": "https://wpnews.pro/news/add-a-ci-gate-for-mcp-contract-coverage-in-10-minutes.jsonld"}}