mcpField
C
Covenant

Covenant

Local
matthiasmeyer.techDeveloper Tools0Updated 1w ago

About Covenant

Covenant is a Rust command-line tool for detecting MCP server interface changes, aimed at teams maintaining servers and checking compatibility in CI. It snapshots interfaces to a lockfile and classifies changes by direction and required SemVer impact.

Key features

  1. 01Interface snapshots and lockfiles
  2. 02Breaking-change detection
  3. 03Direction-aware schema diffing
  4. 04Interface hygiene checks
  5. 05SARIF and GitHub Action support
  6. 06stdio and Streamable HTTP

Use cases

  1. 01Block breaking interface changes in CI
  2. 02Review required version bumps
  3. 03Check tool descriptions and parameter schemas
  4. 04Compare interface lockfiles offline

MCP support

Covenant performs the MCP handshake and reads tool, resource, and prompt listings to inspect a server's interface; it does not call tools. It connects over stdio or Streamable HTTP.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

No install method listed yet

We haven’t collected a package or remote endpoint for this server. Follow the instructions in the project README.

Repository

Tools

No tool list yet

Local servers expose tools only once running on your machine, and the maintainer has not provided a tool list.

Details

From the project README

Part of the StudioMeyer MCP Stack — Built in Mallorca 🌴 · ⭐ if you use it

mcp-covenant

crates.io CI OpenSSF Scorecard License: MIT

Contract & breaking-change detection for Model Context Protocol servers — semver for your MCP interface.

When you ship a typed library you have a public API and tooling that screams when you break it. MCP servers have neither: they just serve whatever tools/list returns today. Rename a tool, add a required argument, narrow an enum — every agent built on your server breaks, and nothing in your pipeline noticed.

mcp-covenant is one static binary that snapshots your server's interface into a committed lockfile and fails CI when a change would break existing clients — classified the way a human would: breaking / minor / patch.

$ mcp-covenant check --baseline mcp-covenant.lock -- node dist/server.js
mcp-covenant: 3 change(s) — required version bump: MAJOR

  BREAKING (2)
    x tool:legacy — tool was removed  [tool.removed]
    x tool:search → inputSchema.properties.limit — new required property  [schema.property.required.added]
  MINOR (1)
    + tool:newtool — new tool  [tool.added]
# exit code 1 → the job fails

Why a Rust one

The idea isn't new — there are already several schema-drift / contract tools for MCP, all in Node, Python or the JVM. mcp-covenant is the one that's a single static binary: nothing to npm install, no Python venv, no JVM in your CI image. Drop it into any pipeline — Go shops, Rust shops, bare Alpine containers — and it talks MCP over stdio or Streamable HTTP.

It's also direction-aware, which is the part most drift tools get wrong (see below).

Companion to mcp-armor (runtime defense) and mcp-gauntlet (pre-deploy fuzz + load). mcp-covenant is the interface-stability leg; mcp-herald (spec migration) and mcp-passport (registry publish gate) complete the stack.


Install

cargo install mcp-covenant

Or build from source:

git clone https://github.com/studiomeyer-io/mcp-covenant
cd mcp-covenant && cargo build --release
# binary at ./target/release/mcp-covenant

A leaner stdio-only build (no HTTP transport, fewer dependencies):

cargo install mcp-covenant --no-default-features

Use it in three commands

1. Snapshot your current interface into a baseline you commit to git:

mcp-covenant snapshot -o mcp-covenant.lock -- node dist/server.js
# or against a running HTTP server:
mcp-covenant snapshot -o mcp-covenant.lock --http https://my-server.example/mcp

2. Check in CI — non-zero exit on a breaking change:

mcp-covenant check --fail-on breaking -- node dist/server.js

3. Lint the interface for schema hygiene (the things that quietly hurt tool selection):

$ mcp-covenant lint -- node dist/server.js
mcp-covenant lint: 2 finding(s) (0 error, 1 warning, 1 info)

  WARNING (1)
    tool:newtool — tool has no description; the model cannot tell when to call it  [tool.missing_description]
  INFO (1)
    tool:search → limit — parameter has no description  [tool.param.missing_description]

Everything also runs fully offline against two lockfiles — no server needed:

mcp-covenant check --baseline v1.lock --against v2.lock
mcp-covenant lint   --from v1.lock

How it classifies changes

The interesting part: a tool's inputSchema is what a caller sends; its outputSchema is what a caller receives. The same structural change has opposite blast radius depending on direction, and mcp-covenant models both.

changeinput (caller sends)output (caller receives)
tool / resource / prompt removedbreaking—
new tool / resource / promptminor—
new required fieldbreakingminor (stronger guarantee)
new optional fieldminorminor
field removedbreaking if required, else minorbreaking (field is gone)
optional → requiredbreakingminor
required → optionalminorbreaking (may now be absent)
type narrowed (e.g. ["string","number"] → string)breakingminor
enum value addedminor (accepts more)breaking (unknown value)
enum value removedbreaking (rejects it)minor
array gains an items schemabreaking (elements now constrained)minor
array drops its items schemaminorbreaking (elements now unconstrained)
additionalProperties: true → falsebreaking—
description / title changedpatchpatch

Nested object properties and array items are diffed recursively. A keyword that is absent on one side is compared as empty: a schema without properties declares no fields, and required counts even for a field the schema never declares. The overall result is the most severe change found, which maps to the semver bump you owe your users.


CI

GitHub Action
# .github/workflows/mcp-contract.yml
name: MCP contract
on: [pull_request]
jobs:
  contract:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: studiomeyer-io/[email protected]
        with:
          command: "node dist/server.js"   # or: http: https://my-server/mcp
          baseline: mcp-covenant.lock
          fail-on: breaking
Raw, any CI
mcp-covenant check --fail-on breaking -- node dist/server.js
SARIF → GitHub code scanning
mcp-covenant check --format sarif -- node dist/server.js > covenant.sarif
# then upload with github/codeql-action/upload-sarif

Findings show up inline on the PR, anchored to your mcp-covenant.lock.


The lockfile

mcp-covenant.lock is plain, pretty-printed, deterministically ordered JSON — commit it and review it like any other lockfile. A regeneration with no interface change is byte-identical, so a noisy diff is the signal.

{
  "covenant_version": "0.1.1",
  "captured_at_unix": 1750000000,
  "server": { "name": "demo", "version": "1.0.0", "protocolVersion": "2025-11-25" },
  "surface": {
    "tools": [ { "name": "search", "description": "Search the catalog.", "inputSchema": { … } } ],
    "resources": [],
    "prompts": []
  }
}

Scope

mcp-covenant is read-only: it does the initialize handshake and calls tools/list, resources/list, prompts/list — it never calls a tool. It models the slice of JSON Schema that MCP tools actually use (type, enum, properties, required, items, additionalProperties), not the entire spec. See CONTRIBUTING.md for the classification rules and how to add one.

License

MIT © StudioMeyer

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.