{"slug": "your-mcp-server-will-drift-from-your-app-here-s-a-build-gate-that-stops-it", "title": "Your MCP server will drift from your app. Here's a build gate that stops it.", "summary": "A developer building RyTask, an open-source project tracker, created a CI gate that ensures every UI feature has a corresponding MCP tool, preventing drift between the application and its agent interface. The gate checks that each capability declared in a module's test plan has a matching MCP tool and vice versa, failing the build if parity is broken. The approach treats AI agents as first-class clients, maintaining full parity between human and agent access.", "body_md": "When I added an MCP server to RyTask (an open-source project tracker), I made one promise:\n\nanything 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\n\nprove, and fail the build over.## The shape of the system\n\nEvery business module in RyTask declares the capabilities it owns and the MCP tools that expose them, in one file:\n\n``` js\n// work-items/module.testplan.ts\nexport const workItemsTestPlan = {\n  capabilities: ['create', 'update', 'assign', 'comment', 'logTime', ...],\n  mcpTools:     ['create_work_item', 'update_work_item', 'assign_work_item', ...],\n}\n```\n\nA registry aggregates every module's tools. The MCP server is built from that same registry — there's no separate hand-maintained list to drift.\n\n## The gate\n\n`check:mcp-parity`\n\nwalks every capability and asserts a matching tool exists, and every tool maps back to a real capability. One missing pair fails CI:\n\n``` js\nconst missingTool = capabilities.filter(c => !toolFor(c))\nconst orphanTool  = tools.filter(t => !capabilityFor(t))\nif (missingTool.length || orphanTool.length) {\n  console.error('MCP parity broken:', { missingTool, orphanTool })\n  process.exit(1)\n}\n```\n\nIt currently reports\n\n49/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\n\nAI 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.\n\nRyTask 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\n\ndeclared-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:\n\ngithub.com/ali-maher-m/RyTask. I'd love feedback on the approach — especially from anyone else building MCP servers for real products.", "url": "https://wpnews.pro/news/your-mcp-server-will-drift-from-your-app-here-s-a-build-gate-that-stops-it", "canonical_source": "https://dev.to/alimaherofficial/your-mcp-server-will-drift-from-your-app-heres-a-build-gate-that-stops-it-454m", "published_at": "2026-06-12 22:25:29+00:00", "updated_at": "2026-06-12 22:43:27.403686+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-products", "mlops"], "entities": ["RyTask", "MCP"], "alternates": {"html": "https://wpnews.pro/news/your-mcp-server-will-drift-from-your-app-here-s-a-build-gate-that-stops-it", "markdown": "https://wpnews.pro/news/your-mcp-server-will-drift-from-your-app-here-s-a-build-gate-that-stops-it.md", "text": "https://wpnews.pro/news/your-mcp-server-will-drift-from-your-app-here-s-a-build-gate-that-stops-it.txt", "jsonld": "https://wpnews.pro/news/your-mcp-server-will-drift-from-your-app-here-s-a-build-gate-that-stops-it.jsonld"}}