
Research
/Security News
737 Chrome VPN Extensions Linked to Brand Impersonation and Browser Traffic Redirection
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.
@fernforge/mcp-conform
Advanced tools
Author-side pre-publish conformance & safety linter for MCP (Model Context Protocol) servers — eslint for your MCP server. Checks tool annotations, schema hygiene, tool-poisoning/injection patterns, and registry/distribution metadata before you publish. C
An eslint for your MCP server. It's a deterministic, author-side conformance and safety linter you run before publishing a Model Context Protocol server to npm, PyPI, or the official MCP registry.
It catches the things that get servers bounced from app directories or make agents call your tools wrong: missing tool annotations, thin or ambiguous schemas, tool-poisoning patterns in descriptions, and incomplete registry metadata. Every issue comes with a one-line fix.
npx github:fernforge/mcp-conform --cmd "node dist/index.js"
mcp-conform — 7 tool(s) checked
delete_record
✖ error ann/missing-destructive-hint Tool "delete_record" may modify state but does not set destructiveHint.
fix: Set annotations.destructiveHint (true for irreversible ops like delete).
✖ error safety/injection-phrase Tool description contains an injection-style phrase (instruction override).
fix: Remove instruction-like text; describe behavior, don't issue commands to the agent.
1 error · 4 warning · 5 info
Conformance score: 76/100 FAIL
No LLM key, no network, fully deterministic. It's a linter, not a model, so it's safe to run in CI, free to run a thousand times a day, and its verdict never drifts.
It lints what actually ships. Point it at your server's launch command and it starts the server over stdio, calls tools/list, and inspects the real schemas your users will receive, not a guess from your source.
A drop-in GitHub Action scores every PR and writes a job summary.
The MCP ecosystem is shipping tens of thousands of servers, and the app directories have gotten strict about what they accept.
Bad tool annotations are the top cause of rejection from the ChatGPT and Claude app directories. The spec says a client must assume the worst case (destructive, open-world) when a hint is missing, so if you don't set readOnlyHint / destructiveHint / openWorldHint / title, clients treat your safe read tool as dangerous.
Tool descriptions are an injection surface. They're injected straight into the agent's context, so an "ignore previous instructions" line or an invisible Unicode payload in a description is a real tool-poisoning vector.
The official registry now does namespace-verified publishing. Reverse-DNS names, a server.json manifest, and clean package metadata are part of being publishable and discoverable.
The community is drafting a pre-publish conformance checklist (modelcontextprotocol Discussion #2682). mcp-conform automates it.
Existing MCP security tools are consumer/runtime-side: they scan servers you're about to install. mcp-conform works the other way. It makes your server conformant before anyone installs it.
Run it straight from the repo, no install needed:
npx github:fernforge/mcp-conform --cmd "node dist/index.js"
Or pull it from npm:
npx mcp-conform --cmd "node dist/index.js"
npm install --save-dev mcp-conform
Requires Node ≥ 18. The MCP SDK is an optional peer dependency, only needed for live --cmd introspection (most projects already have it).
mcp-conform always lints your project metadata (package.json, server.json) and takes the tools to lint from one of three sources:
mcp-conform --cmd "node dist/index.js"
mcp-conform --cmd "python -m my_server"
mcp-conform --cmd "uvx my-mcp-server"
It launches the server over stdio, initializes a client, and lints the real tools/list output plus capability/transport hygiene.
mcp-conform --manifest tools.json
Where tools.json is either a tools/list result ({ "tools": [...] }) or a bare array of tool definitions. Handy for Python/Go servers or for snapshotting in tests.
mcp-conform # checks package.json + server.json in the current dir
mcp-conform --cmd "node dist/index.js" --json # machine-readable
mcp-conform --cmd "node dist/index.js" --markdown --out report.md
mcp-conform --cmd "node dist/index.js" --min-score 80 # fail under 80
mcp-conform --cmd "node dist/index.js" --max-warnings 0 # fail on any warning
mcp-conform exits non-zero when there's any error-severity finding, so it fails CI by default. Tighten the gate with --min-score and --max-warnings.
Add .github/workflows/mcp-conform.yml to your server repo:
name: MCP Conformance
on: [pull_request, push]
jobs:
conform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci && npm run build
- uses: fernforge/mcp-conform@v0.1.0
with:
cmd: "node dist/index.js"
min-score: "80"
It writes a Markdown report to the job summary and fails the check when the score drops below your threshold.
| Category | Examples |
|---|---|
| Annotations | missing readOnlyHint / destructiveHint / openWorldHint; missing human-readable title; a delete_*/update_* tool marked read-only |
| Schema hygiene | missing/thin tool description; params with no description or type; missing inputSchema; additionalProperties unset; missing outputSchema |
| Safety / tool-poisoning | "ignore previous instructions" & concealment phrases; hidden zero-width / bidi / Unicode-tag characters; oversized descriptions; high-agency (exec/sql/write_file) tools understating their reach |
| Distribution metadata | missing name/version/license/repository; no keywords or no mcp keyword; no bin/main; no engines |
| Registry | no server.json; name not in reverse-DNS namespace form; missing manifest fields |
| Transport (live only) | advertised capability with nothing served, or tools served without the capability advertised |
Every finding carries a rule id, a severity (error / warning / info), and a concrete fix. The conformance score (0–100) is a single deterministic number you can track over time.
import { lint, introspect, loadProjectMetadata } from "mcp-conform";
const live = await introspect({ command: "node", args: ["dist/index.js"] });
const meta = await loadProjectMetadata(process.cwd());
const result = lint({ ...live, ...meta });
console.log(result.score, result.pass);
for (const f of result.findings) console.log(f.severity, f.rule, f.message);
--fix for the mechanical annotation/metadata gapsmcpconform.json) to set severities and disable rulesmcpconform-config-recommended ruleset that tracks the community conformance checklist as it finalizesIssues and rule suggestions welcome — the rule set is meant to track the standard as it forms.
MIT © fernforge
FAQs
Author-side conformance, safety & spec-migration linter for MCP (Model Context Protocol) servers — eslint for your MCP server. Checks tool annotations, schema hygiene, tool-poisoning/injection patterns, registry/distribution metadata, and scans your sourc
The npm package @fernforge/mcp-conform receives a total of 12 weekly downloads. As such, @fernforge/mcp-conform popularity was classified as not popular.
We found that @fernforge/mcp-conform demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.