Reference

The rules

Every tool's inputSchema is read against a client profile, the definitions are costed in tokens, and the tool text is checked for hostile patterns. Each finding carries a stable code, a severity, and a location.

How a target is checked

The pipeline is static and has no rendering step. A saved payload never starts a server; a server command is spoken to over stdio and then closed.

  1. Read the target

    A saved tools/list payload, an mcp.json config, or a server command. The payload is accepted as an array, a {"tools":[...]} object, or a raw tools/list response.

  2. Pick a profile

    The client profile decides which names, root shapes, and keywords are valid. claude is the default; openai, gemini, foundry, copilot, and generic are available.

  3. Run the rules

    Schema rules, description rules, safety rules, and cost rules emit issues, each with a severity and a location such as read file:inputSchema.properties.path.

  4. Report

    Print text or stable JSON, write SARIF 2.1.0, and exit 0, 1, 2, or 3 for CI.

The rule codes

Every rule, grouped by what it protects: name, schema shape, description, safety, and cost.
Code Severity What it catches
MCP-001errorInvalid or missing tool name; the profile's allowed characters and length limit are enforced.
MCP-002errorDuplicate tool name; clients collapse duplicates and may call the wrong tool.
MCP-003errorMissing or non-object inputSchema; clients require one.
MCP-004errorRoot inputSchema is not type: object, so requests fail on every call.
MCP-005errorRoot $ref, allOf, anyOf, or oneOf a client will not resolve, so the tool is dropped or errors.
MCP-006errorNo properties object at the root; strict clients reject the whole request.
MCP-007warningProperty name characters some clients do not accept, or a name longer than 64 characters.
MCP-008errorA required entry with no matching property; strict clients reject the tool.
MCP-009warningA property that declares no type, leaving its type ambiguous to the model.
MCP-010warningThe OpenAPI keyword nullable, which is not valid JSON Schema; use a union type.
MCP-011infoA $schema draft that differs from the profile's preferred draft.
MCP-012warningA missing description, so the model cannot judge when to call the tool.
MCP-013infoA very long description, which is re-sent with every request.
MCP-020warningPrompt-injection-like tool text; describe capabilities plainly so the server is not treated as hostile.
MCP-021warningInvisible or bidirectional Unicode characters, a known tool-poisoning technique.
MCP-022warningAn unconstrained shell, file, SQL, or URL sink property reachable from tool input.
MCP-030warningA server whose tool definitions exceed the token budget.
MCP-031infoA single tool whose definition is oversized on its own.
MCP-032warningTool definitions that consume over 20% of a 200k-token context window before the first message.

Client profiles

A profile describes what one client accepts. The same payload can pass for one profile and fail for another, which is why the profile is explicit in every run.

What each built-in profile requires.
Profile Tool name Property name Root type: object Root $ref / combinators Root properties Draft
claude[A-Za-z0-9_-], 1-64[A-Za-z0-9_.-], 1-64requiredrejectedrequired2020-12
openai[A-Za-z0-9_-], 1-64[A-Za-z0-9_-], 1-64requiredrejectedrequiredany
gemini[A-Za-z0-9_-], 1-64[A-Za-z0-9_.-], 1-64requiredrejectedrequiredany
foundry[A-Za-z0-9_-], 1-64[A-Za-z0-9_-], 1-64requiredrejectedrequiredany
copilot[A-Za-z0-9_-], 1-64[A-Za-z0-9_.-], 1-64requiredrejectedrequiredany
generic[A-Za-z0-9_-], 1-128anyrequiredcombinators allowedrequiredany

An example schema

A valid tool for the claude profile: an object root, typed properties, a constrained sink, and required that matches properties.

{
  "name": "read_file",
  "description": "Read a UTF-8 text file under the data directory.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "maxLength": 256,
        "pattern": "^/srv/data/[A-Za-z0-9_./-]+$"
      }
    },
    "required": ["path"]
  }
}