eslint-plugin-mcp-sdk-security
MCP SDK security — tool-input validation and transport hygiene
AI-Optimized Security
Every rule includes CWE, OWASP, and CVSS metadata for AI assistants to provide precise, context-aware fixes.
Install
npm install -D oxlint-plugin-mcp-sdk-security{ "jsPlugins": ["oxlint-plugin-mcp-sdk-security"], "rules": { "mcp-sdk-security/no-code-injection-in-tool": "error", "mcp-sdk-security/no-command-injection-in-tool": "error", "mcp-sdk-security/no-credential-leak-in-tool": "error", "mcp-sdk-security/no-duplicate-tool-name": "warn", "mcp-sdk-security/no-path-traversal-in-tool": "error", "mcp-sdk-security/no-predictable-session-id": "error", "mcp-sdk-security/no-shared-stateless-transport": "error", "mcp-sdk-security/no-sql-injection-in-tool": "error", "mcp-sdk-security/no-ssrf-in-tool": "error", "mcp-sdk-security/no-tool-description-injection": "error", "mcp-sdk-security/no-untrusted-stdio-command": "error", "mcp-sdk-security/no-untrusted-tool-metadata-in-prompt": "error", "mcp-sdk-security/no-unvalidated-tool-args": "error", "mcp-sdk-security/require-http-transport-hardening": "error", "mcp-sdk-security/require-tool-input-schema": "error" }}import { defineConfig } from 'vite-plus';export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-mcp-sdk-security'], rules: { 'mcp-sdk-security/no-code-injection-in-tool': 'error', 'mcp-sdk-security/no-command-injection-in-tool': 'error', 'mcp-sdk-security/no-credential-leak-in-tool': 'error', 'mcp-sdk-security/no-duplicate-tool-name': 'warn', 'mcp-sdk-security/no-path-traversal-in-tool': 'error', 'mcp-sdk-security/no-predictable-session-id': 'error', 'mcp-sdk-security/no-shared-stateless-transport': 'error', 'mcp-sdk-security/no-sql-injection-in-tool': 'error', 'mcp-sdk-security/no-ssrf-in-tool': 'error', 'mcp-sdk-security/no-tool-description-injection': 'error', 'mcp-sdk-security/no-untrusted-stdio-command': 'error', 'mcp-sdk-security/no-untrusted-tool-metadata-in-prompt': 'error', 'mcp-sdk-security/no-unvalidated-tool-args': 'error', 'mcp-sdk-security/require-http-transport-hardening': 'error', 'mcp-sdk-security/require-tool-input-schema': 'error', }, },});oxlint-plugin-mcp-sdk-security re-exports eslint-plugin-mcp-sdk-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.
Live from GitHub
This content is fetched directly from README.md on GitHub and cached for 1 hour.
⭐ If this plugin caught a real bug for you, star the repo — it's the signal that keeps these rules maintained.
Description
Security rules for code built on @modelcontextprotocol/sdk.
Scope: this plugin lints the MCP SDK's API shapes — registerTool, transports, handler signatures. It does not inspect MCP wire traffic, which isn't visible from source. Every rule gates on the SDK actually being imported, so it stays silent in files that don't use MCP.
- Why — a linter nobody reads protects nothing. We would rather miss a finding than spend your attention on one that was never real.
- How — evidence, not names. A rule fires on what the code does, resolved through the AST and ESLint's own scope analysis.
- What — every finding carries its fix, in prose for a human and as structured JSON for an agent. Security rules add a CWE mapping and, where assigned, a CVSS score.
That trade costs recall, and we measure it: methodology · results · a false positive is a bug.
Getting Started
- To check out the guide, visit eslint.interlace.tools. 📚
oxlint / Vite+ — the same rules under the same mcp-sdk-security/<rule> IDs, without ESLint:
npm install oxlint-plugin-mcp-sdk-security --save-dev// .oxlintrc.json
{ "jsPlugins": ["oxlint-plugin-mcp-sdk-security"] }// vite.config.ts
import { defineConfig } from 'vite-plus';
export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-mcp-sdk-security'] } });ESLint:
npm install eslint-plugin-mcp-sdk-security --save-dev⚙️ Configuration Presets
| Preset | Rules (error, except no-duplicate-tool-name at warn) | Description |
|---|---|---|
minimal | no-command-injection-in-tool, require-tool-input-schema | Only the rules whose every finding is a defect by construction. |
recommended | no-code-injection-in-tool, no-command-injection-in-tool, no-credential-leak-in-tool, no-duplicate-tool-name, no-path-traversal-in-tool, no-predictable-session-id, no-shared-stateless-transport, no-sql-injection-in-tool, no-ssrf-in-tool, no-tool-description-injection, no-untrusted-stdio-command, no-untrusted-tool-metadata-in-prompt, no-unvalidated-tool-args, require-http-transport-hardening, require-tool-input-schema | The default. Every rule, each at error from CVSS 7.0 up and warn below. |
strict | no-code-injection-in-tool, no-command-injection-in-tool, no-credential-leak-in-tool, no-duplicate-tool-name, no-path-traversal-in-tool, no-predictable-session-id, no-shared-stateless-transport, no-sql-injection-in-tool, no-ssrf-in-tool, no-tool-description-injection, no-untrusted-stdio-command, no-untrusted-tool-metadata-in-prompt, no-unvalidated-tool-args, require-http-transport-hardening, require-tool-input-schema | Every rule, at its recommended level. Where a new rule lands before its false-positive profile is measured. |
Supported servers: @modelcontextprotocol/sdk (v1), the v2 split packages
(@modelcontextprotocol/server, client, core, node, express, hono,
fastify), and mcp-handler / @vercel/mcp-adapter. Every rule stays silent
in a file that imports none of them.
What the rules cover:
- Tool handlers — a tool argument,
request.params.argumentsor aResourceTemplatevariable reaching a process (no-command-injection-in-tool), a file path (no-path-traversal-in-tool), a request host (no-ssrf-in-tool), SQL text (no-sql-injection-in-tool) oreval/vm(no-code-injection-in-tool); the environment or the caller's token in a result, or that token forwarded upstream (no-credential-leak-in-tool); the schema/handler contract (require-tool-input-schema,no-unvalidated-tool-args); one name registered twice (no-duplicate-tool-name). - Model-facing text — a tool, prompt or resource description built from
text a client, a remote service or a file controls
(
no-tool-description-injection). - HTTP transports — DNS-rebinding protection,
allowedHostsand authentication (require-http-transport-hardening), a stateless transport or server shared across requests (no-shared-stateless-transport, CVE-2026-25536), and predictable session IDs (no-predictable-session-id). - Clients — a server's tool metadata written into an LLM prompt
(
no-untrusted-tool-metadata-in-prompt), and a stdio server command taken from a tool argument, a network response or project config (no-untrusted-stdio-command).
Each taint rule follows the value inside its handler — used directly, built
into a string, or derived — and resolves sinks to the module that defines them.
Tool handlers are this plugin's scope, so on the same line it may report
alongside eslint-plugin-node-security
(no-shell-injection, detect-non-literal-fs-filename, no-ssrf,
detect-eval-with-expression) or
eslint-plugin-secure-coding
(no-sql-injection), which cover the same sinks outside MCP handlers. Each
rule's doc states its overlap.
Usage
// eslint.config.js
import mcpSdkSecurity from 'eslint-plugin-mcp-sdk-security';
export default [
mcpSdkSecurity.configs.recommended,
];Or wire the rules yourself:
import mcpSdkSecurity from 'eslint-plugin-mcp-sdk-security';
export default [
{
plugins: { 'mcp-sdk-security': mcpSdkSecurity },
rules: {
'mcp-sdk-security/require-tool-input-schema': 'error',
},
},
];oxlint
Every rule in this plugin runs on oxlint as well as ESLint:
{ "jsPlugins": ["eslint-plugin-mcp-sdk-security/oxlint"] }📦 Compatibility
See the ESLint Version Support Policy for the full matrix.
Rules
Legend
| Icon | Description |
|---|---|
| 💼 | Recommended: Included in the recommended preset. |
| ⚠️ | Warns: Set to warn in recommended preset. |
| 🔧 | Auto-fixable: Automatically fixable by the --fix CLI option. |
| 💡 | Suggestions: Providing code suggestions in IDE. |
| 🚫 | Deprecated: This rule is deprecated. |
| 🟢 | Type-unaware: AST-only, runs in oxlint JS-plugin tier. |
| 🟡 | Type-aware (refining): pure-AST primary path; types refine precision. |
| 🟠 | Type-aware (graceful): requires TS program; silent without it. |
| Rule | CWE | OWASP | CVSS | Description | 🧠 | 💼 | ⚠️ | 🔧 | 💡 | 🚫 |
|---|---|---|---|---|---|---|---|---|---|---|
| no-code-injection-in-tool | CWE-95 | A03:2021 | Disallow an MCP tool argument reaching eval, new Function or a vm context as code. | 🟢 | 💼 | |||||
| no-command-injection-in-tool | CWE-78 | A03:2021 | Disallow an MCP tool argument choosing the command a child_process call runs. | 🟢 | 💼 | |||||
| no-credential-leak-in-tool | CWE-200 | A01:2021 | Disallow an MCP tool returning the server's environment or the caller's token, or forwarding that token ups… | 🟢 | 💼 | |||||
| no-duplicate-tool-name | CWE-694 | A04:2021 | Disallow registering or listing two MCP tools with the same name on one server. | 🟢 | ⚠️ | |||||
| no-path-traversal-in-tool | CWE-22 | A01:2021 | Disallow an MCP tool argument choosing the file an fs call reads, writes or deletes without a containment c… | 🟢 | 💼 | |||||
| no-predictable-session-id | CWE-330 | A02:2021 | Disallow an MCP sessionIdGenerator that returns a counter, a timestamp, Math.random() or a constant. | 🟢 | 💼 | |||||
| no-shared-stateless-transport | CWE-488 | A04:2021 | Disallow sharing one stateless Streamable HTTP transport or one MCP server across requests. | 🟢 | 💼 | |||||
| no-sql-injection-in-tool | CWE-89 | A03:2021 | Disallow an MCP tool argument reaching the text of a SQL query instead of its parameters. | 🟢 | 💼 | |||||
| no-ssrf-in-tool | CWE-918 | A10:2021 | Disallow an MCP tool argument choosing the host an outbound HTTP request is sent to. | 🟢 | 💼 | |||||
| no-tool-description-injection | CWE-1427 | A03:2021 | Disallow MCP tool, prompt and resource descriptions built from text a client, a remote service or a file co… | 🟢 | 💼 | |||||
| no-untrusted-stdio-command | CWE-78 | A03:2021 | Disallow an MCP client spawning a stdio server whose command comes from a tool argument, a network response… | 🟢 | 💼 | |||||
| no-untrusted-tool-metadata-in-prompt | CWE-1427 | A03:2021 | Disallow an MCP client writing a server's tool, prompt or resource metadata into an LLM prompt instead of i… | 🟢 | 💼 | |||||
| no-unvalidated-tool-args | CWE-20 | A03:2021 | Disallow a tool handler reading an argument its declared input schema does not include. | 🟢 | 💼 | |||||
| require-http-transport-hardening | CWE-346 | A05:2021 | Require an MCP HTTP server transport to validate the Host header and a network-reachable MCP server to auth… | 🟢 | 💼 | |||||
| require-tool-input-schema | CWE-20 | A03:2021 | Require an input schema when an MCP tool handler reads arguments. | 🟢 | 💼 |
⭐ Support & follow
If this plugin caught a real bug for you, star the repo — stars are the signal that keeps the Interlace ESLint ecosystem maintained — and follow the writeups on Dev.to for the benchmarks and security research behind these rules.
🔗 Related ESLint Plugins
Part of the Interlace ESLint ecosystem — AI-native rules with LLM-optimized error messages:
Security
Code quality
| Plugin | Downloads | Description |
|---|---|---|
eslint-plugin-cli-floor | CLI floor for commander, yargs and burgee. | |
eslint-plugin-conventions | Team-specific habits and styles. | |
eslint-plugin-import-next | Fast cycle + import-graph analysis. | |
eslint-plugin-maintainability | Cognitive load and clean-code patterns. | |
eslint-plugin-modernization | ESNext migration + syntax evolution. | |
eslint-plugin-modularity | Structural integrity and DDD patterns. | |
eslint-plugin-operability | Production readiness and resource health. | |
eslint-plugin-react-a11y | React accessibility / WCAG. | |
eslint-plugin-react-features | React best practices and optimization. | |
eslint-plugin-reliability | Runtime stability and error safety. |
📄 License
MIT © Ofri Peretz
Building secure JavaScript with Interlace? Star the repo to get new rules and CWE coverage as we ship them — or follow the AI-code-security benchmarks behind them.