All 27 checks with why-it-matters prose, severity, and cross-references to related audits.
Without a JSON Schema `inputSchema`, AI clients have no contract for what arguments a tool accepts — they guess at parameter names, types, and format. OWASP LLM09 (Misinformation) is the direct risk: the AI constructs plausible-looking but wrong invocations, producing silently incorrect behavior. Missing required-field markers mean the AI may omit critical parameters; missing descriptions mean it cannot distinguish a file path from a query string. In prompt-injection scenarios (CWE-20, OWASP A03), undefined inputs widen the attack surface because the server cannot reject malformed or adversarial arguments before execution.
Why this severity: Critical because a missing inputSchema means the AI client has no enforceable contract, so every tool invocation is a guess that can silently corrupt behavior or enable injection (CWE-20).
mcp-server.tool-definitions.input-schemasSee full patternTool names are the primary routing signal for any AI client selecting between dozens of tools from multiple connected MCP servers. A name like `run` or `do` gives the model nothing to distinguish your tool from a similarly-named one in another server. Mixed conventions — some `snake_case`, some `camelCase`, some `kebab-case` — force the model to pattern-match without a consistent rule, increasing mistaken invocations. When tool selection fails silently, the correct action is never taken and the user sees wrong or missing output with no explanation.
Why this severity: High because inconsistent or vague names cause the AI to select the wrong tool, especially in multi-server sessions where name collisions produce unpredictable routing behavior.
mcp-server.tool-definitions.tool-namingSee full patternA tool's description is the only text an AI reads when deciding whether to call it, and when to choose it over a similar tool. A description that just repeats the name (`"Deletes a file"` for a tool named `delete_file`) adds zero signal. Missing side-effect disclosures are especially dangerous: OWASP LLM09 surfaces here when the model cannot distinguish a read-only inspection tool from one that permanently deletes records, potentially auto-approving destructive calls without user confirmation.
Why this severity: High because poor descriptions cause the AI to invoke the wrong tool or fail to warn users about destructive side effects, leading to unrecoverable operations without confirmation.
mcp-server.tool-definitions.tool-descriptionsSee full patternClients use resource URIs as stable identifiers to fetch, cache, and subscribe to server data. A bare string like `config` or `logs` is not a URI — it breaks RFC 6570 template parsing and prevents clients from constructing valid resource reads. Without `mimeType`, clients cannot determine whether to render content as markdown, JSON, or binary, which causes display failures or silently mangled output. These are fundamental contract violations that break resource discovery for any client following the MCP spec.
Why this severity: High because invalid URI templates and missing mimeType fields cause resource reads to fail at the protocol level, making all registered resources inaccessible to compliant clients.
mcp-server.tool-definitions.resource-urisSee full patternPrompt templates without argument definitions leave clients guessing at what inputs to supply. A prompt named `review` with no description gives the client no basis for surfacing it to the user at the right moment or pre-filling arguments. Duplicate prompt names cause non-deterministic selection. These failures map directly to MCP Spec noncompliance: the `prompts/list` response becomes misleading, and clients that rely on argument descriptions to build UI will silently omit required context.
Why this severity: Medium because undescribed or argument-free prompts degrade discoverability and usability without causing immediate security or data failures.
mcp-server.tool-definitions.prompt-templatesSee full patternThe MCP content type system (`text`, `image`, `resource`) tells clients how to render tool results. Returning a raw string instead of a `content` array means clients receive output they cannot reliably parse or display. Image tools that omit `mimeType` from `data` content leave clients unable to decode the bytes. These are protocol conformance failures — a client following the MCP spec will reject or misrender non-conformant responses, turning working tool calls into user-visible errors.
Why this severity: Low because malformed return structures cause display or parse failures in clients but do not expose data or enable attacks; the impact is limited to incorrect rendering.
mcp-server.tool-definitions.return-content-typesSee full patternMCP tool annotations (`readOnlyHint`, `destructiveHint`, `openWorldHint`) are the mechanism by which clients decide whether to auto-approve a tool call or prompt the user for confirmation. Without annotations, the MCP spec defaults `destructiveHint` to `true` and `readOnlyHint` to `true` — meaning a tool that permanently deletes files could be treated as read-only and auto-approved, bypassing any confirmation dialog. Clients that implement safe-by-default behavior rely entirely on these fields to gate destructive operations.
Why this severity: Low because missing annotations degrade client safety UX but do not themselves cause data loss — the risk depends on how aggressively the client auto-approves unannotated tools.
mcp-server.tool-definitions.tool-annotationsSee full patternAn MCP server without a connection example in its README forces every new user to read source code before they can use it. Unlike standard npm packages where the import pattern is obvious, MCP clients require a specific JSON config block with `command`, `args`, and `env` — there is no discoverable default. The MCP spec defines `mcpServers` configuration as the integration point; without it documented, adoption stalls and users connect incorrectly, leading to silent failures or version mismatches.
Why this severity: Info because missing connection docs create friction and integration errors but do not expose security vulnerabilities or corrupt data.
mcp-server.tool-definitions.sdk-exampleSee full patternJSON-RPC 2.0 is the wire protocol underpinning every MCP interaction. A response missing `"jsonrpc": "2.0"` will be rejected by any compliant client. Responses that don't echo the request `id` leave the client unable to correlate responses to outstanding requests — causing hangs or misrouted results. Non-standard error formats (`{'error': 'message'}` instead of `{'error': {'code': -32601, 'message': '...'}}`) break client error handling. These are CWE-116 (improper encoding) failures that make the server non-interoperable.
Why this severity: Critical because a malformed JSON-RPC envelope breaks the entire protocol layer — clients reject non-conformant responses and the server becomes non-functional regardless of tool correctness.
mcp-server.transport-protocol.jsonrpc-messagesSee full patternWhen an MCP server uses stdio transport, stdout is the JSON-RPC channel. A single `console.log()` in a tool handler writes non-JSON text into that channel, corrupting the message stream. Clients receive parse errors or silently drop subsequent messages. This is the most common MCP server defect in production — debug logging left in handlers from development. CWE-116 (improper encoding/escaping) applies directly: the output stream carries protocol data, not freeform text, and mixing the two is a protocol violation that makes the server non-functional.
Why this severity: Critical because any `console.log()` in a stdio-transport server corrupts the protocol channel, causing immediate and total communication failure with connected clients.
mcp-server.transport-protocol.stdio-transportSee full patternServers offering HTTP/SSE transport must produce strictly formatted SSE events with `data:` prefixes and proper `Content-Type: text/event-stream`. Omitting the `data:` prefix causes clients to receive unparseable chunks. Missing CORS headers (CWE-942) block browser-based MCP clients entirely via same-origin policy. Broken session ID management means concurrent clients corrupt each other's message streams. These are protocol-level failures that make the HTTP transport path non-functional for any client not on localhost.
Why this severity: Medium because SSE format errors and missing CORS headers break HTTP transport for specific client types without affecting stdio-connected clients.
mcp-server.transport-protocol.http-transportSee full patternThe MCP handshake (`initialize` → server capabilities → `notifications/initialized`) is a mandatory protocol sequence. A server that does not handle the `initialize` method returns a method-not-found error on the very first client message, causing immediate disconnection before any tool can be called. Processing tool requests before the handshake completes violates the protocol ordering guarantee and causes undefined behavior in clients that enforce the sequence. This is a baseline conformance requirement with no workaround on the client side.
Why this severity: Critical because a missing `initialize` handler causes clients to disconnect on first contact — no tools, resources, or prompts are reachable until the handshake completes successfully.
mcp-server.transport-protocol.initialize-handshakeSee full patternThe `protocolVersion` field in the initialize response is how MCP clients determine whether this server is compatible with features they intend to use. An invented version string (e.g., `"1.0"`) does not match any valid MCP release and breaks version-gated features in strict clients. A missing `protocolVersion` entirely leaves clients unable to negotiate compatibility. The MCP spec uses date-based versions (e.g., `"2024-11-05"`) as the canonical format — non-date strings signal that the server was not built against the actual specification.
Why this severity: High because an invalid or missing `protocolVersion` breaks version negotiation, which can prevent clients from enabling features the server actually supports.
mcp-server.transport-protocol.version-negotiationSee full patternJSON-RPC 2.0 defines notifications as messages with no `id` — they require no response, and sending one violates the spec. A server that sends error responses to `notifications/initialized` (because it tries to echo the id that isn't there) causes clients to receive unexpected extra messages, which can desync the message stream. A server that crashes on an unknown notification type (`notifications/cancelled`, `notifications/roots/list_changed`) can be triggered by any client action that emits those events, making stability fragile in real workloads.
Why this severity: Low because notification handling errors cause protocol drift and occasional crashes rather than data exposure, and most SDK-based servers get this right automatically.
mcp-server.transport-protocol.notificationsSee full patternMCP clients send `ping` requests to verify a server is alive before timing out a connection or showing an error to the user. A server that returns `-32601 Method not found` on ping tells the client it is disconnected, triggering reconnection logic or user-visible errors even when the server is running fine. A server that returns a non-standard value (e.g., the string `"pong"` instead of an empty object `{}`) breaks clients that validate response shape. Ping is cheap to implement correctly and expensive to get wrong.
Why this severity: Low because a broken ping handler causes spurious connection errors and reconnection overhead but does not expose data or corrupt tool results.
mcp-server.transport-protocol.ping-supportSee full patternJSON-RPC error codes carry semantic meaning that MCP clients use to determine how to display and recover from errors. Using HTTP-style codes (404, 500) instead of JSON-RPC codes (-32601, -32603) causes client error handlers to misclassify failures — a method-not-found error processed as an internal error may suppress retry logic or show the wrong message. CWE-703 (improper check or handling of exceptional conditions) applies: error codes must accurately describe the failure type for clients to respond correctly, especially in automated AI workflows where error classification drives next-step decisions.
Why this severity: High because incorrect error codes cause clients to mishandle failures — retrying internal errors, suppressing user-facing messages, or misrouting recoverable vs. non-recoverable conditions.
mcp-server.error-resilience.structured-errorsSee full patternMCP tools that let exceptions propagate unhandled either crash the server process or produce an opaque JSON-RPC internal error (`-32603`) with no actionable detail. CWE-703 (improper check of exceptional conditions) is the root; CWE-209 (generation of error messages with sensitive information) is the follow-on risk when raw stack traces leak internal file paths and dependency versions into tool output. The correct MCP pattern is to catch exceptions inside the handler and return `isError: true` with a descriptive, scrubbed message — keeping the server alive and giving the AI something useful to act on.
Why this severity: High because unhandled exceptions crash the server or surface raw stack traces, taking down all tools simultaneously and potentially exposing internal implementation details.
mcp-server.error-resilience.tool-error-catchSee full patternWhen a client sends a request for an unrecognized method, the JSON-RPC 2.0 spec requires a `-32601 Method not found` error response. A custom server without a fallback case silently drops the request — the client hangs indefinitely waiting for a response that never arrives. This is CWE-703: the unhandled case is a real input condition in production (a newer client calling a method the server hasn't implemented yet). Returning the wrong error code, like `-32603 Internal error`, misleads the client into treating a known gap as an unexpected server failure.
Why this severity: High because missing a default error case causes client hangs on any unrecognized method call, which in agentic workflows can freeze an entire session without a visible error.
mcp-server.error-resilience.method-not-foundSee full patternMalformed JSON is a normal input condition in production — network truncation, client bugs, and injection attempts all produce broken payloads. A server that crashes on `JSON.parse()` failure (CWE-1286: improper validation of syntactic correctness) takes down all tools with no error sent to the client. OWASP A03 (Injection) is the active risk when valid JSON with adversarial parameter values reaches a handler that doesn't validate types or required fields. CWE-20 (improper input validation) covers both: the server must reject bad input before it reaches business logic.
Why this severity: High because malformed input can crash the server process (denying all tools) or reach handlers that execute with unvalidated, attacker-controlled values.
mcp-server.error-resilience.malformed-inputSee full patternA tool that calls `fetch()` with no timeout will hang indefinitely if the remote service is unresponsive — the MCP client freezes waiting for a result that never arrives. A tool that executes shell commands with no timeout can be kept running permanently by a hung subprocess, blocking the server for all clients. CWE-400 (uncontrolled resource consumption) is the mechanism; ISO 25010 performance-efficiency is the quality attribute violated. In agentic workflows where the AI chains multiple tool calls, a single hung tool halts the entire session.
Why this severity: Medium because missing timeouts cause hangs under degraded network or process conditions rather than immediate failures, but the impact is a frozen session with no recovery path short of restarting the server.
mcp-server.error-resilience.timeout-handlingSee full patternMCP servers running as child processes receive SIGINT when the user presses Ctrl+C and SIGTERM when the parent process shuts down. Without signal handlers, the Node.js process exits immediately (`SIGINT` default), potentially mid-write on an in-progress JSON-RPC response. The client receives a truncated or empty message and marks the server as crashed. CWE-404 (improper resource shutdown) covers this: open database connections, file handles, and HTTP keep-alives are abandoned rather than closed, which can leave the remote systems in inconsistent state.
Why this severity: Medium because abrupt termination corrupts in-progress responses and leaks resources, but the immediate impact is limited to the session in progress at shutdown time.
mcp-server.error-resilience.graceful-shutdownSee full patternThe `capabilities` object in the initialize response is the contract that tells clients which MCP features to use. Declaring `resources` with `subscribe: true` but providing no subscription implementation causes clients to attempt subscriptions that fail silently. Implementing prompts but not declaring `prompts` in capabilities means clients never discover them — the feature is invisible. These mismatches are a form of contract violation: the server lies about its interface, and clients built against that lie fail in ways that are hard to diagnose.
Why this severity: High because capabilities mismatches cause systematic failures — either clients invoking unimplemented features or silently missing features the server provides — both producing broken integrations.
mcp-server.security-capabilities.capability-declarationSee full patternTool arguments come from AI model output, which can be manipulated via prompt injection (OWASP LLM01). An MCP tool that executes a shell command, writes a file, or queries a database using arguments it hasn't validated is wide open to CWE-78 (OS command injection) and CWE-22 (path traversal). Even without a malicious actor, an AI model generating plausible-but-wrong parameter values (wrong types, out-of-range numbers) will hit unvalidated code paths and produce crashes or corrupted state. Input schema validation is the gating control before any side effect executes.
Why this severity: Critical because unvalidated tool inputs enable injection attacks (CWE-78, CWE-22) and prompt injection exploitation (OWASP LLM01) that can execute arbitrary commands or access unauthorized files.
mcp-server.security-capabilities.input-validationSee full patternMCP tool responses are injected directly into AI context windows — any credential that appears in a response is now in the model's context and may be logged, cached, or included in future prompts. CWE-312 (cleartext storage of sensitive information) and CWE-532 (sensitive information in log files) are both active: a tool that echoes `process.env` in an error message or includes the `Authorization` header from a response object has leaked the credential to every downstream log, trace, and context export. OWASP A02 (Cryptographic Failures) and OWASP LLM02 (sensitive information disclosure) both apply.
Why this severity: High because credentials in tool output are injected into AI context, where they are visible to logs, traces, and potentially future model calls — a difficult-to-detect, persistent exposure.
mcp-server.security-capabilities.no-credential-leaksSee full patternA file-reading tool that accepts arbitrary paths can read `/etc/passwd`, `~/.ssh/id_rsa`, or any credential file on the host system — this is CWE-22 (path traversal), rated OWASP A01 (Broken Access Control). In MCP servers where the AI model constructs file paths, OWASP LLM01 (prompt injection) is the threat vector: an injected instruction tells the model to read sensitive paths and the tool executes without bounds checking. Symlink escapes are the bypass for naive prefix checks: a symlink at `/workspace/escape` pointing to `/etc` passes the `startsWith('/workspace')` test but reads outside the allowed scope.
Why this severity: High because unbounded file system access allows reading any file on the host — including SSH keys, environment files, and secrets — through path traversal or symlink escapes triggered via prompt injection.
mcp-server.security-capabilities.fs-access-boundedSee full patternA `read_file` tool with no size limit will attempt to load a 5GB log file into Node.js heap, causing an out-of-memory crash that takes down every tool in the server simultaneously. A database query tool with no `LIMIT` clause can return millions of rows, exhausting memory and making the response unparseable. CWE-400 (uncontrolled resource consumption) and CWE-770 (allocation of resources without limits) are the mechanisms. These are not theoretical edge cases — agentic AI workflows routinely hit large files and broad queries when exploring unfamiliar codebases or databases.
Why this severity: Medium because resource exhaustion from oversized responses crashes the server process, but it requires the AI or user to trigger an operation against genuinely large data sources.
mcp-server.security-capabilities.resource-limitsSee full patternMCP defines a structured logging protocol via `notifications/message` with severity levels (`debug`, `info`, `warning`, `error`, etc.) that clients can display, filter, and route to observability systems. A server that only uses `console.error` keeps all operational visibility on stderr — invisible to the connected AI client and to any MCP-aware monitoring tool. When a server-side failure occurs during an agentic run, the client has no programmatic signal to surface the failure; the AI sees only the missing tool result with no explanation.
Why this severity: Low because the absence of MCP-native logging reduces observability without causing data loss or security failures — clients still function, but operational diagnosis is harder.
mcp-server.security-capabilities.mcp-loggingSee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open MCP Server Audit