MCP Security Scanner Alerts Are Leads, Not Verdicts

A scanner cannot admit an MCP server. Pair alert triage with sandboxed runtime tests, capability policy, and drift checks.

Saturday, July 25, 2026Omid Saffari
MCP Security Scanner Alerts Are Leads, Not Verdicts

An MCP security scanner should open an investigation, not close an admission decision. Ship the server only after its code, runtime behavior, identity boundary, and capability drift survive the same gate.

A scanner finding is evidence, not a trust decision

The useful output of an MCP security scanner is a hypothesis your team can reproduce. It is not a certificate, and a clean report is not proof that a server is safe.

A July 2026 study built a runtime-capable corpus from 64,611 unique MCP servers, with 37,288 supporting dynamic analysis, then evaluated eight publicly available scanners across static, dynamic, and hybrid approaches. At least one scanner flagged 96.89% of the interactable servers, but no server was flagged by all eight. The reported server sets had an average pairwise Jaccard similarity of 15.66%, which means the scanners rarely agreed on what belonged in the risky set.

Manual validation made the decision problem sharper. Average alert precision was 45.53%, while overall recall against the study's confirmed-vulnerability benchmark was 24.17%. A noisy report can consume review time without identifying an exploitable path. A quiet report can still miss a known vulnerability. Those measurements are from the researchers' runtime study of MCP servers and scanner reliability, not a benchmark run by DVNC.dev.

That rule extends the broader MCP server security controls into a release gate a platform team can run on every artifact.

Keep scanners, but demote them from judge to evidence collector

Static and runtime scanners should stay in the gate because they expose different failure surfaces. Static analysis can inspect source, dependency locks, install scripts, unsafe sinks, and authentication code without executing the package. Runtime analysis can observe the tool manifest, protocol behavior, outbound requests, file access, identity handling, and errors that exist only after initialization.

The study does not justify ignoring scanner output. Its recall ground truth contains 10 CVEs affecting 38 MCPZoo servers, and the authors explicitly describe that set as not exhaustive. Precision also varied substantially across tools and configurations. The reliable conclusion is narrower: a scanner result needs validation before it becomes a trust decision.

Use the finding itself to choose the next test:

  • A command-execution finding should identify the tool handler, the input that reaches the sink, and the process privilege at execution time.
  • A token finding should prove which issuer and audience the server accepts, not merely detect an authorization header.
  • A tool-poisoning finding should preserve the exact description or schema change and show whether the client would expose it without a new approval.
  • A network finding should name the destination reached under a controlled invocation and whether policy allowed it.

This matters because 37.6% of the classified tools in the study exposed high capabilities such as command execution, file modification, or data transmission. Capability is not a vulnerability by itself. It is the reason the server needs a narrow identity, a constrained runtime, and a policy that denies undeclared behavior.

A physical MCP server admission line where provenance, scanner evidence, sandbox behavior, and capability policy each control release
A scanner contributes one class of evidence. Admission requires every control to agree.

Admit an artifact and a policy, never a package name

An MCP server is ready only when the exact artifact and its allowed behavior are reviewed together. “Approved package” is too broad because a new release, dependency, tool schema, scope, or destination can change the trust boundary.

  1. Pin provenance before analysis

    Resolve the repository owner, commit, package digest, dependency lock, build recipe, entry command, transport, and expected tool manifest. Store that record with the admission decision. A registry name or a mutable tag is discovery metadata, not identity.

    Treat every new digest as a new candidate. Reusing an old approval for new code defeats the gate before scanning begins.

  2. Turn scanner alerts into reviewable claims

    Persist the scanner version, rule, file and symbol, suspected source-to-sink path, affected tool, and raw evidence. Confirm whether the path is reachable through the exposed MCP schema and whether a sandboxed invocation reproduces it.

    Reject a confirmed unsafe path. For a false positive, record why it is unreachable or contained, who owns that judgment, and which artifact digest it applies to. Do not suppress the rule globally because one package produced noise.

  3. Exercise the protocol inside a restricted runtime

    Start the server with synthetic credentials, a read-only file system except for an explicit scratch location, and outbound access denied except for named test services. Run initialization, inspect tools/list, call non-destructive tools, send malformed inputs, test missing arguments and concurrent operations, and observe failures, restarts, file access, and egress.

    The official MCP Inspector runs through npx. It exposes tool schemas and descriptions, executes tools with custom inputs, displays results, surfaces logs and notifications, and supports edge-case testing. Use it for interactive diagnosis, then automate the same assertions in CI.

    Official MCP Inspector documentation showing server testing capabilities
    MCP Inspector is useful for protocol diagnosis; the admission verdict still belongs to your policy and runtime evidence.
  4. Bind every tool to an enforceable capability

    Map each tool to its effect, required scope, permitted destinations, data boundary, and approval mode. Unknown tools and schema changes fail closed. Mutating or destructive calls require an explicit approval tied to the arguments the user is about to authorize.

    MCP's official security guidance says servers MUST NOT accept tokens that were not explicitly issued for the MCP server. Servers implementing authorization MUST verify every inbound request and MUST NOT use a session as authentication. Use progressive least-privilege scopes, and log every scope elevation with a correlation ID.

An illustrative policy for a ticketing server can stay small enough to review:

YAML
server:
  artifact: "digest:<pinned-artifact>"
  transport: "stdio"
  network: "deny"

tools:
  tickets.search:
    effect: "read"
    scope: "tickets.read"
    approval: "not-required"
    destinations: ["support-api.test"]

  tickets.close:
    effect: "mutate"
    scope: "tickets.write"
    approval: "required"
    destinations: ["support-api.test"]

on_unknown_tool: "deny"
on_schema_change: "quarantine"
on_new_destination: "quarantine"

The policy is intentionally separate from the model prompt. A prompt can guide tool selection; it cannot enforce process isolation, token audience, egress, or approval.

Run a reference admission test that fails closed

A useful admission test proves both the allowed path and the blocked path. Consider a SaaS platform team evaluating an MCP server with tickets.search and tickets.close for an internal support agent.

Create a synthetic tenant with realistic ticket shapes but no customer data. Give the server a principal that can read that tenant and cannot mutate it. Mount a canary file outside the permitted scratch location, inject a synthetic secret, and deny outbound traffic except to the test authorization issuer and ticket API.

Then exercise the boundary:

  • tickets.search with a valid tenant should return only synthetic records and produce no unexpected file or network access.
  • A path, URL, or shell fragment in a search field should remain data. Any new process, private-network request, or canary read is a rejection.
  • tickets.close under the read principal should fail authorization before mutation.
  • The write path should require an approval that displays the tool and material arguments. Replaying the call without that approval should remain denied.
  • A renamed tool, wider input schema, new OAuth scope, or new destination should quarantine the candidate rather than inherit the old approval.

The official MCP security guidance requires explicit user approval before a local server command executes and recommends a sandbox with minimal default privileges plus restricted file-system and network access. The NSA's MCP security guidance makes the same operational point: unneeded access paths should be explicitly denied at runtime.

Log the decision as structured evidence, not a free-form debug line:

JSON
{
  "artifact_digest": "digest:<pinned-artifact>",
  "manifest_hash": "digest:<tool-manifest>",
  "tool": "tickets.close",
  "principal": {
    "subject": "synthetic-reviewer",
    "audience": "support-mcp",
    "scopes": ["tickets.read"]
  },
  "policy": {
    "decision": "deny",
    "reason": "scope_missing"
  },
  "egress_destination": null,
  "output_hash": null,
  "correlation_id": "<review-run>"
}

The NSA guidance recommends logging exact invocation parameters, identities, and, where feasible, cryptographic hashes of outputs. Redact secrets at ingestion, but retain enough normalized argument data to reproduce why policy allowed or denied the call.

Trust expires when the server or tool surface changes

Approval should be invalidated by meaningful drift, not renewed on a calendar alone. Pin the artifact digest, tool manifest, schemas, authorization issuer and audience, declared scopes, destinations, and runtime policy as one admission record.

At startup and after an update, fetch the tool surface and compare it with that record. Quarantine an unknown tool, a broader schema, a new destination, a silent scope change, or a different artifact. Require a human reviewer to approve new mutating capability and its arguments. Read-only additions still need policy review, but they should not force an approval prompt on every safe invocation once admitted.

A physical capability-drift checkpoint comparing a pinned MCP artifact and tool manifest with runtime behavior before allowing or quarantining it
Trust follows the pinned artifact and capability manifest. Unexplained drift goes to quarantine.

The continuing evidence should answer:

  • Which artifact and policy version handled the call?
  • Which client and user identity reached which tool?
  • Which scopes and approval authorized the effect?
  • Which network destination and data boundary were involved?
  • Did the result, tool manifest, or schema differ from the admitted baseline?

Maintain an inventory of deployed MCP servers and tools with versions, patch history, owners, and known security concerns. Differential reports matter because a server can change its port, tool surface, dependency graph, or egress behavior without changing the business label engineers use for it.

Runtime validation costs build time and review attention, so spend it on change. Run the full restricted suite for every new artifact, then make the stable path cheap by comparing pinned manifests and enforcing policy on every call. Do not save minutes by carrying trust across a digest change.

Block capability drift first

The next control after scanning should be a deny-by-default capability diff. It catches the moment a previously reviewed server asks for new power, which is precisely where a point-in-time scanner report stops helping.

Logs support forensics, sandboxing limits impact, and scoped identity constrains access. The drift gate connects them: it prevents an unknown tool, schema, scope, or destination from quietly inheriting yesterday's trust. Teams building the server itself can apply the same rule inside the broader internal API MCP delivery path.

Frequently asked questions

Can an MCP security scanner prove that a server is safe?

No. A scanner can find evidence worth investigating, but safety depends on the exact artifact, reachable runtime behavior, identity boundary, capability policy, and ongoing drift controls. The MCPZoo study found low average precision and recall alongside substantial disagreement between scanners.

Should an engineering team use static or runtime MCP scanning?

Use both. Static analysis sees source, dependencies, and install behavior without execution. Runtime testing exposes protocol behavior, tool changes, network and file access, authorization failures, and effects that source heuristics may not confirm.

How do you test an MCP server before installing it?

Pin the artifact, run it with synthetic credentials inside a restricted environment, inspect its declared tools and schemas, exercise valid and adversarial inputs, observe file and network access, and compare the result with an explicit policy. Reject or quarantine anything the policy did not declare.

Does sandboxing replace MCP authorization?

No. Sandboxing constrains what the process can reach after code runs. Authorization decides which principal may invoke which tool and scope before the effect occurs. A reliable deployment needs both boundaries.

Last Updated

Jul 25, 2026

CategoryMCP
Newsletter

One letter, every week. Working systems — not hot takes.

Build logs, agentic engineering decisions, agent failures, evals, and what survives real users. Sent weekly, never more.

Weekly. No spam. Unsubscribe anytime.