7 min read
MCP Contract Tools
AI coding agents write breaking changes without realising it because they cannot see your API contract. StateAnchor solves this by exposing the contract state as five MCP tools plus a .cursor/rules/stateanchor.md generator. When Claude Code, Cursor, or Copilot is about to modify a protected endpoint, it calls the gate first -- and gets back the same verdict StateAnchor would return on push.
Not to be confused with the MCP Server guide, which generates an MCP server from your spec so AI agents can call your API at runtime. The contract tools below are the reverse: they let the AI agent query StateAnchor about your contract before it writes the code.
The five tools
All five tools are exposed via a single authenticated endpoint: POST /api/projects/[projectId]/mcp. The request body selects the tool and passes parameters. Every tool is fail-open -- errors return a structured error: true object, never crash the agent mid-completion.
| Tool | What it does |
|---|---|
list_protected_endpoints | Returns every endpoint under active drift protection. The agent uses this to decide whether a file it is about to edit is gate-protected. |
check_if_breaking | Given a proposed change ({ endpoint, change_type, field }), returns the lane the gate would produce plus safe_alternatives. If breaking: true, the agent knows to stop. |
get_endpoint_contract | Returns the full IR entry for one endpoint -- parameters, request body, response schema, auth. The agent reads the contract before writing code. |
get_consumer_impact | Returns which SDK methods and languages depend on the endpoint plus recent near-miss ledger entries. Budget defense when a removal is proposed. |
suggest_safe_evolution | Returns the INFO-lane changes the agent could make instead -- optional fields, new endpoints, deprecation flags, relaxed constraints. |
Example API calls
Checking a proposed change
POST /api/projects/proj_01HABC/mcp
Content-Type: application/json
{
"tool": "check_if_breaking",
"params": {
"endpoint": "GET /users/{id}",
"change_type": "field_removed",
"field": "email"
}
}Response:
{
"breaking": true,
"lane": "ERR",
"reason": "field_removed on GET /users/{id} is always-breaking -- gate would block on push.",
"safe_alternatives": [
"Deprecate email instead of removing -- add `deprecated: true` to the schema.",
"Add a new optional field with the replacement, keep the old one until next major version."
]
}Listing every protected endpoint
POST /api/projects/proj_01HABC/mcp
{ "tool": "list_protected_endpoints" }{
"endpoints": [
{ "method": "GET", "path": "/users/{id}", "name": "getUser", "protection": "active" },
{ "method": "POST", "path": "/users", "name": "createUser", "protection": "active" }
],
"count": 2
}Batch change evaluation
When an AI agent plans several edits at once, pass proposed_changes as an array. The tool returns per-change results in input order plus a compound risk assessment. Compound lane precedence: ERR > WARN > INFO. Any ERR or WARN in the batch flips safe_to_proceed to false.
POST /api/projects/proj_01HABC/mcp
{
"tool": "check_if_breaking",
"params": {
"proposed_changes": [
{ "endpoint": "GET /users/{id}", "change_type": "field_removed", "field": "email" },
{ "endpoint": "POST /users", "change_type": "field_added_optional", "field": "nickname" }
]
}
}Response:
{
"compound_lane": "ERR",
"compound_reason": "2 change(s) evaluated: 1 ERR, 0 WARN, 1 INFO",
"safe_to_proceed": false,
"per_change_results": [
{
"breaking": true,
"lane": "ERR",
"reason": "field_removed on GET /users/{id} is always-breaking -- gate would block on push.",
"safe_alternatives": [
"Deprecate email instead of removing -- add `deprecated: true` to the schema.",
"Add a new optional field with the replacement, keep the old one until next major version."
]
},
{
"breaking": false,
"lane": "INFO",
"reason": "field_added_optional on POST /users is additive -- safe.",
"safe_alternatives": []
}
]
}Batch evaluation is backward-compatible: passing a single change object still returns the original { breaking, lane, reason, safe_alternatives } shape. Arrays -- or an object with a top-level proposed_changes array -- trigger the compound path.
Getting consumer impact before a removal
POST /api/projects/proj_01HABC/mcp
{
"tool": "get_consumer_impact",
"params": { "method": "GET", "path": "/users/{id}" }
}{
"endpoint": "GET /users/{id}",
"affected_sdk_methods": [
{ "language": "typescript", "method": "getUser" },
{ "language": "python", "method": "getUser" },
{ "language": "go", "method": "getUser" }
],
"affected_languages": ["typescript", "python", "go"],
"near_miss_history": [
{ "id": "nm_...", "created_at": "2026-04-12T...", "endpoint": "GET /users/{id}",
"kind": "field_removed", "summary": "blocked on push abc123 -- email field" }
]
}The cursor-rules generator
A single GET returns a ready-to-commit .cursor/rules/stateanchor.md file tailored to your project. Drop it into your repo and Cursor (and Claude Code, which reads the same format) will see the rules on every request.
# Fetch the rules file curl -H "Authorization: Bearer $STATEANCHOR_TOKEN" \ https://stateanchor.dev/api/projects/proj_01HABC/mcp/cursor-rules \ -o .cursor/rules/stateanchor.md
The generated file lists your protected endpoints and every always-breaking / always-safe change kind, plus a ready-to-paste check_if_breaking call the agent can make before writing code. Example output:
# StateAnchor API Contract Rules
# Auto-generated for payments-api. Regenerate: GET /api/projects/proj_01HABC/mcp/cursor-rules
## Protected Endpoints
These endpoints have active drift protection. Modifying them may trigger a
gate block on the next push.
- `GET /users/{id}`
- `POST /users`
## Always Breaking Changes (never make these)
- `endpoint_removed`
- `field_removed`
- `type_changed`
- `auth_changed`
- `enum_value_removed`
- `oneOf_anyOf_modified`
- `required_param_added`
- `optional_param_now_required`
- `param_removed`
- `response_field_removed`
- `response_field_type_changed`
- `response_schema_type_changed`
- `success_status_removed`
- `validation_constraints_tightened`
## Always Safe Changes
- `endpoint_added`
- `field_added_optional`
- `description_changed`
- `endpoint_key_collision`
- `deprecated_flag_added`
- `constraints_relaxed`
- `optional_status_code_added`
- `metadata_changed`
## Check Before You Code
Call the StateAnchor API to verify any proposed change:
`POST https://stateanchor.dev/api/projects/proj_01HABC/mcp`
Body: `{ "tool": "check_if_breaking", "params": { "endpoint": "METHOD /path", "change_type": "field_removed", "field": "email" } }`
Response shape: `{ breaking, lane, reason, safe_alternatives }`. If `breaking: true`,
stop and escalate -- do not write the change. If `breaking: false`, proceed and
include the response `reason` in your commit message.Integrating with Cursor
Cursor reads rule files from .cursor/rules/ automatically. Commit the generated file to your repo; every future Cursor session sees the rules without any additional configuration.
.cursor/
rules/
stateanchor.md # ← generated file, check it inIntegrating with Claude Code
Claude Code reads CLAUDE.md at the repo root plus any file referenced from it. Add a line to your CLAUDE.md pointing at the generated rules:
## API contract rules Before modifying any endpoint under `app/api/`, read `.cursor/rules/stateanchor.md` and call `check_if_breaking` as documented there.
Integrating with GitHub Copilot
Copilot’s chat follows the same .cursor/rules/ convention as of its 2026 Q1 update. Commit the generated file and Copilot picks it up automatically in IDEs that support the chat sidecar.
Auth and rate limits
All five tools require a Clerk-authenticated session with ownership of the project (same check as the dashboard). The cursor-rules endpoint accepts either a session cookie or a project-scoped API token. The endpoint is rate-limited at the same tier as other project-scoped reads -- a typical AI-agent session makes well under the limit.
Why this exists
A model that writes code without knowing the contract is a permanent drift source. StateAnchor’s gate catches the breaking change at push time, but by then the diff has already been written, reviewed, and possibly merged. The MCP contract tools close the loop earlier: the agent sees the same categorical gate decision the human would see, before the diff exists.