{"slug": "lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp", "title": "Lint your MCP server before you publish it (an eslint for MCP)", "summary": "A developer built mcp-conform, a linter for Model Context Protocol servers that checks for missing tool annotations, injection-prone descriptions, and registry readiness before publication. The tool runs against the live server over stdio, inspecting real schemas to catch conformance issues early.", "body_md": "If you've shipped a [Model Context Protocol](https://modelcontextprotocol.io) server, you've probably hit this: the server *works* in your editor, you publish it, and then agents call your tools wrong — or worse, a client flags it as unsafe and it never makes it into the ChatGPT or Claude app directories.\n\nThere's no `eslint`\n\nfor this. So I built one: ** mcp-conform** — a deterministic, author-side conformance & safety linter you run\n\n```\nnpx github:fernforge/mcp-conform --cmd \"node dist/index.js\"\nmcp-conform — 7 tool(s) checked\n\ndelete_record\n  ✖ error  ann/missing-destructive-hint  Tool may modify state but does not set destructiveHint.\n         fix: Set annotations.destructiveHint (true for irreversible ops like delete).\n  ✖ error  safety/injection-phrase       Description contains an instruction-override phrase.\n         fix: Describe behavior, don't issue commands to the agent.\n\n1 error · 4 warning · 5 info\nConformance score: 76/100   FAIL\n```\n\nThree things changed under MCP authors' feet, and they all bite at publish time:\n\n**1. Missing tool annotations are the #1 reason servers get rejected from app directories.** The spec says a client *must assume the worst case* — destructive, open-world — when a hint is absent. So if you don't set `readOnlyHint`\n\n/ `destructiveHint`\n\n/ `openWorldHint`\n\n/ `title`\n\n, your harmless read tool gets treated as dangerous, and your destructive tool ships with no warning at all.\n\n**2. Tool descriptions are an injection surface.** Descriptions are fed straight into the agent's context. An \"ignore previous instructions…\" line — or an invisible Unicode payload — sitting in a description is a real **tool-poisoning** vector. You want that caught in CI, not in a security write-up about your package.\n\n**3. The official registry now does namespace-verified publishing.** Reverse-DNS names, a `server.json`\n\nmanifest, and clean package metadata are part of being publishable and discoverable now, not nice-to-haves.\n\nMost existing MCP security tooling is **consumer-side** — it scans servers you're about to *install*. `mcp-conform`\n\nis **author-side and shift-left**: it makes *your* server conformant before anyone installs it.\n\n`readOnlyHint`\n\n, `destructiveHint`\n\n, `openWorldHint`\n\n, `title`\n\n.`package.json`\n\n/ `server.json`\n\nreadiness for the registry.The interesting part: point it at your server's **launch command** and it starts the server over stdio, calls `tools/list`\n\n, and inspects the *real* schemas your users will receive — not a guess parsed from your source. That catches the gap between what your code looks like and what your server actually serves.\n\n```\n# lint the live, running server\nnpx github:fernforge/mcp-conform --cmd \"node dist/server.js\"\n\n# or a saved tools/list dump, with a CI gate\nnpx github:fernforge/mcp-conform --manifest tools.json --min-score 80\n```\n\nIt's a linter, not a model. Safe to run in CI, free to run a thousand times a day, and its verdict never drifts. There's a drop-in **GitHub Action** that scores every PR and writes a job summary, so a regression in your tool metadata fails the build like any other lint error.\n\n```\nnpx github:fernforge/mcp-conform --cmd \"<your server launch command>\"\n```\n\nRepo, rules, and the GitHub Action: ** https://github.com/fernforge/mcp-conform** (MIT).\n\nIt's early — if you publish MCP servers, I'd genuinely like to know which checks catch real issues for you and which rules you'd want next. Open an issue or drop a comment.\n\n(Disclaimer: this article was generated by ai)", "url": "https://wpnews.pro/news/lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp", "canonical_source": "https://dev.to/fernforge/lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp-3gb7", "published_at": "2026-06-27 01:51:41+00:00", "updated_at": "2026-06-27 02:34:06.113310+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-safety", "large-language-models"], "entities": ["mcp-conform", "Model Context Protocol", "Fernforge", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp", "markdown": "https://wpnews.pro/news/lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp.md", "text": "https://wpnews.pro/news/lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp.txt", "jsonld": "https://wpnews.pro/news/lint-your-mcp-server-before-you-publish-it-an-eslint-for-mcp.jsonld"}}