# Your MCP server will drift from your app. Here's a build gate that stops it.

> Source: <https://dev.to/alimaherofficial/your-mcp-server-will-drift-from-your-app-heres-a-build-gate-that-stops-it-454m>
> Published: 2026-06-12 22:25:29+00:00

When I added an MCP server to RyTask (an open-source project tracker), I made one promise:

anything a person can do in the UI, an AI agent can do over MCP.No read-only second-class agent access. Full parity.The problem with promises like that is they rot. You ship a new feature, wire it into the UI and the REST API, and forget the MCP tool. Three sprints later your "100% parity" is 86% parity and you don't know it. So I made parity a thing CI can

prove, and fail the build over.## The shape of the system

Every business module in RyTask declares the capabilities it owns and the MCP tools that expose them, in one file:

``` js
// work-items/module.testplan.ts
export const workItemsTestPlan = {
  capabilities: ['create', 'update', 'assign', 'comment', 'logTime', ...],
  mcpTools:     ['create_work_item', 'update_work_item', 'assign_work_item', ...],
}
```

A registry aggregates every module's tools. The MCP server is built from that same registry — there's no separate hand-maintained list to drift.

## The gate

`check:mcp-parity`

walks every capability and asserts a matching tool exists, and every tool maps back to a real capability. One missing pair fails CI:

``` js
const missingTool = capabilities.filter(c => !toolFor(c))
const orphanTool  = tools.filter(t => !capabilityFor(t))
if (missingTool.length || orphanTool.length) {
  console.error('MCP parity broken:', { missingTool, orphanTool })
  process.exit(1)
}
```

It currently reports

49/49. The day I add a "duplicate project" feature and forget the tool, the build goes red and tells me exactly which tool is missing. Parity stopped being a docs claim and became an invariant.## Why this matters beyond my project

AI agents are becoming real users of software. If your agent surface is a hand-curated subset of your product, it will always lag the UI, and your users' agents will hit walls the humans don't. Treating the agent as a first-class client — held to the same coverage by the same CI that guards everything else — is, I think, where a lot of tools are going to end up.

RyTask does the same trick for a few other invariants: module boundaries (you can't import another module's internals), multi-tenancy (every tenant-scoped query is auto-constrained to the caller's org at the repository layer, and tests assert cross-tenant isolation against a real Postgres), and a "closed testing" gate that fails the build if a

declared-requiredtest file is merely missing.It's all open source (AGPL-3.0), built solo. If you want to see the gates in action, the repo's here:

github.com/ali-maher-m/RyTask. I'd love feedback on the approach — especially from anyone else building MCP servers for real products.
