require-tool-input-schema
Require an input schema when registering an MCP tool
Require an input schema when registering an MCP tool.
- CWE: CWE-20 — Improper Input Validation
- OWASP: A03:2021 — Injection
- CVSS: 7.5 (High)
- Recommended:
error
Why
An MCP tool registered without an input schema receives whatever arguments the client sends. The handler then runs on unvalidated, attacker-influenced input — the entry point for tool poisoning and argument injection. Where the handler reaches a filesystem, shell, or network sink, the missing schema is the difference between a constrained parameter and arbitrary input.
The schema is also what the model sees when deciding how to call the tool. Without it, the model guesses the shape, which makes malformed and adversarial calls likelier.
Rule details
The rule fires only in files that import @modelcontextprotocol/sdk. It reports:
registerTool(name, config, handler)whereconfigis an object literal with noinputSchemaproperty.tool(name, handler)— the legacy arity with no schema between the name and the callback.
It deliberately stays silent when it cannot read the configuration: a config passed by reference or built from a spread may well carry the schema, and guessing there would flag correct code.
Incorrect
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
server.registerTool('read_file', { description: 'Read a file' }, async (args) => {
return readFileSync(args.path, 'utf8');
});
server.tool('delete_record', async (args) => db.delete(args.id));Correct
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
server.registerTool('read_file', {
description: 'Read a file',
inputSchema: { path: z.string() },
}, async (args) => {
return readFileSync(args.path, 'utf8');
});
server.tool('delete_record', { id: z.string().uuid() }, async (args) => db.delete(args.id));When not to use it
If the server registers tools through a wrapper that injects the schema, the rule cannot see it and will report the wrapper's call site. Disable it there rather than repeating the schema.
Further reading
Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.